update for HEAD-2003091401
[reactos.git] / subsys / win32k / objects / text.c
index b5e7026..0950c5d 100644 (file)
@@ -1,3 +1,22 @@
+/*
+ *  ReactOS W32 Subsystem
+ *  Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/* $Id$ */
 
 
 #undef WIN32_LEAN_AND_MEAN
 #include <win32k/dc.h>
 #include <win32k/text.h>
 #include <win32k/kapi.h>
+#include <include/error.h>
 #include <ft2build.h>
 #include FT_FREETYPE_H
 
 #include "../eng/handle.h"
 
 #include <include/inteng.h>
+#include <include/text.h>
+#include <include/eng.h>
+#include <include/palette.h>
 
 #define NDEBUG
 #include <win32k/debug1.h>
@@ -28,9 +51,25 @@ typedef struct _FONTTABLE {
 FONTTABLE FontTable[256];
 INT FontsLoaded = 0;
 
-BOOL InitFontSupport()
+BOOL FASTCALL InitFontSupport(VOID)
 {
   ULONG error;
+  UINT File;
+  static WCHAR *FontFiles[] =
+  {
+  L"\\SystemRoot\\media\\fonts\\Vera.ttf",
+  L"\\SystemRoot\\media\\fonts\\helb____.ttf",
+  L"\\SystemRoot\\media\\fonts\\timr____.ttf",
+  L"\\SystemRoot\\media\\fonts\\VeraBd.ttf",
+  L"\\SystemRoot\\media\\fonts\\VeraBI.ttf",
+  L"\\SystemRoot\\media\\fonts\\VeraIt.ttf",
+  L"\\SystemRoot\\media\\fonts\\VeraMoBd.ttf",
+  L"\\SystemRoot\\media\\fonts\\VeraMoBI.ttf",
+  L"\\SystemRoot\\media\\fonts\\VeraMoIt.ttf",
+  L"\\SystemRoot\\media\\fonts\\VeraMono.ttf",
+  L"\\SystemRoot\\media\\fonts\\VeraSe.ttf",
+  L"\\SystemRoot\\media\\fonts\\VeraSeBd.ttf"
+  };
 
   error = FT_Init_FreeType(&library);
   if(error)
@@ -38,21 +77,21 @@ BOOL InitFontSupport()
     return FALSE;
   }
 
-#ifndef TODO
-  W32kAddFontResource(L"\\SystemRoot\\media\\fonts\\arial.ttf");
-#endif
-  W32kAddFontResource(L"\\SystemRoot\\media\\fonts\\helb____.ttf");
-  W32kAddFontResource(L"\\SystemRoot\\media\\fonts\\timr____.ttf");
+  for (File = 0; File < sizeof(FontFiles) / sizeof(WCHAR *); File++)
+    {
+    DPRINT("Loading font %S\n", FontFiles[File]);
+
+    NtGdiAddFontResource(FontFiles[File]);
+    }
 
   DPRINT("All fonts loaded\n");
 
   return TRUE;
 }
 
-static NTSTATUS
+static NTSTATUS STDCALL
 GetFontObjectsFromTextObj(PTEXTOBJ TextObj, HFONT *FontHandle, PFONTOBJ *FontObj, PFONTGDI *FontGDI)
 {
-  UINT i;
   NTSTATUS Status = STATUS_SUCCESS;
 
   ASSERT(NULL != TextObj && NULL != TextObj->GDIFontHandle);
@@ -91,7 +130,7 @@ GetFontObjectsFromTextObj(PTEXTOBJ TextObj, HFONT *FontHandle, PFONTOBJ *FontObj
 
 int
 STDCALL
-W32kAddFontResource(LPCWSTR  Filename)
+NtGdiAddFontResource(LPCWSTR  Filename)
 {
   HFONT NewFont;
   PFONTOBJ FontObj;
@@ -171,8 +210,8 @@ W32kAddFontResource(LPCWSTR  Filename)
   FontGDI->face = face;
 
   // FIXME: Complete text metrics
-  FontGDI->TextMetric.tmAscent = face->size->metrics.ascender; // units above baseline
-  FontGDI->TextMetric.tmDescent = face->size->metrics.descender; // units below baseline
+  FontGDI->TextMetric.tmAscent = (face->size->metrics.ascender + 32) / 64; // units above baseline
+  FontGDI->TextMetric.tmDescent = (- face->size->metrics.descender + 32) / 64; // units below baseline
   FontGDI->TextMetric.tmHeight = FontGDI->TextMetric.tmAscent + FontGDI->TextMetric.tmDescent;
 
   DPRINT("Font loaded: %s (%s)\n", face->family_name, face->style_name);
@@ -192,7 +231,7 @@ W32kAddFontResource(LPCWSTR  Filename)
   return 1;
 }
 
-NTSTATUS
+NTSTATUS FASTCALL
 TextIntCreateFontIndirect(CONST LPLOGFONTW lf, HFONT *NewFont)
 {
   PTEXTOBJ TextObj;
@@ -214,8 +253,9 @@ TextIntCreateFontIndirect(CONST LPLOGFONTW lf, HFONT *NewFont)
     }
     else
     {
-      ASSERT(FALSE);
-      Status = STATUS_INVALID_HANDLE;
+/* FIXME */
+/*      ASSERT(FALSE);*/
+      Status = STATUS_INVALID_HANDLE;      
     }
   }
   else
@@ -228,7 +268,7 @@ TextIntCreateFontIndirect(CONST LPLOGFONTW lf, HFONT *NewFont)
 
 HFONT
 STDCALL
-W32kCreateFont(int  Height,
+NtGdiCreateFont(int  Height,
                int  Width,
                int  Escapement,
                int  Orientation,
@@ -263,7 +303,10 @@ W32kCreateFont(int  Height,
 
   if (NULL != Face)
   {
-    Status = MmCopyFromCaller(logfont.lfFaceName, Face, sizeof(logfont.lfFaceName));
+    int Size = sizeof(logfont.lfFaceName) / sizeof(WCHAR);
+    wcsncpy((wchar_t *)logfont.lfFaceName, Face, Size - 1);
+    /* Be 101% sure to have '\0' at end of string */
+    logfont.lfFaceName[Size - 1] = '\0';
   }
   else
   {
@@ -280,7 +323,7 @@ W32kCreateFont(int  Height,
 
 HFONT
 STDCALL
-W32kCreateFontIndirect(CONST LPLOGFONTW lf)
+NtGdiCreateFontIndirect(CONST LPLOGFONTW lf)
 {
   LOGFONTW SafeLogfont;
   HFONT NewFont;
@@ -304,7 +347,7 @@ W32kCreateFontIndirect(CONST LPLOGFONTW lf)
 
 BOOL
 STDCALL
-W32kCreateScalableFontResource(DWORD  Hidden,
+NtGdiCreateScalableFontResource(DWORD  Hidden,
                                      LPCWSTR  FontRes,
                                      LPCWSTR  FontFile,
                                      LPCWSTR  CurrentPath)
@@ -314,7 +357,7 @@ W32kCreateScalableFontResource(DWORD  Hidden,
 
 int
 STDCALL
-W32kEnumFontFamilies(HDC  hDC,
+NtGdiEnumFontFamilies(HDC  hDC,
                           LPCWSTR  Family,
                           FONTENUMPROCW  EnumFontFamProc,
                           LPARAM  lParam)
@@ -324,9 +367,9 @@ W32kEnumFontFamilies(HDC  hDC,
 
 int
 STDCALL
-W32kEnumFontFamiliesEx(HDC  hDC,
+NtGdiEnumFontFamiliesEx(HDC  hDC,
                             LPLOGFONTW  Logfont,
-                            FONTENUMPROCW  EnumFontFamExProc,
+                            FONTENUMEXPROCW  EnumFontFamExProc,
                             LPARAM  lParam,
                             DWORD  Flags)
 {
@@ -335,7 +378,7 @@ W32kEnumFontFamiliesEx(HDC  hDC,
 
 int
 STDCALL
-W32kEnumFonts(HDC  hDC,
+NtGdiEnumFonts(HDC  hDC,
                    LPCWSTR FaceName,
                    FONTENUMPROCW  FontFunc,
                    LPARAM  lParam)
@@ -345,7 +388,7 @@ W32kEnumFonts(HDC  hDC,
 
 BOOL
 STDCALL
-W32kExtTextOut(HDC  hDC,
+NtGdiExtTextOut(HDC  hDC,
                      int  X,
                      int  Y,
                      UINT  Options,
@@ -359,7 +402,7 @@ W32kExtTextOut(HDC  hDC,
 
 BOOL
 STDCALL
-W32kGetAspectRatioFilterEx(HDC  hDC,
+NtGdiGetAspectRatioFilterEx(HDC  hDC,
                                  LPSIZE  AspectRatio)
 {
   UNIMPLEMENTED;
@@ -367,7 +410,7 @@ W32kGetAspectRatioFilterEx(HDC  hDC,
 
 BOOL
 STDCALL
-W32kGetCharABCWidths(HDC  hDC,
+NtGdiGetCharABCWidths(HDC  hDC,
                            UINT  FirstChar,
                            UINT  LastChar,
                            LPABC  abc)
@@ -377,7 +420,7 @@ W32kGetCharABCWidths(HDC  hDC,
 
 BOOL
 STDCALL
-W32kGetCharABCWidthsFloat(HDC  hDC,
+NtGdiGetCharABCWidthsFloat(HDC  hDC,
                                 UINT  FirstChar,
                                 UINT  LastChar,
                                 LPABCFLOAT  abcF)
@@ -387,11 +430,11 @@ W32kGetCharABCWidthsFloat(HDC  hDC,
 
 DWORD
 STDCALL
-W32kGetCharacterPlacement(HDC  hDC,
+NtGdiGetCharacterPlacement(HDC  hDC,
                                  LPCWSTR  String,
                                  int  Count,
                                  int  MaxExtent,
-                                 LPGCP_RESULTS  Results,
+                                 LPGCP_RESULTSW  Results,
                                  DWORD  Flags)
 {
   UNIMPLEMENTED;
@@ -399,7 +442,7 @@ W32kGetCharacterPlacement(HDC  hDC,
 
 BOOL
 STDCALL
-W32kGetCharWidth(HDC  hDC,
+NtGdiGetCharWidth(HDC  hDC,
                        UINT  FirstChar,
                        UINT  LastChar,
                        LPINT  Buffer)
@@ -409,7 +452,7 @@ W32kGetCharWidth(HDC  hDC,
 
 BOOL
 STDCALL
-W32kGetCharWidth32(HDC  hDC,
+NtGdiGetCharWidth32(HDC  hDC,
                          UINT  FirstChar,
                          UINT  LastChar,
                          LPINT  Buffer)
@@ -419,7 +462,7 @@ W32kGetCharWidth32(HDC  hDC,
 
 BOOL
 STDCALL
-W32kGetCharWidthFloat(HDC  hDC,
+NtGdiGetCharWidthFloat(HDC  hDC,
                             UINT  FirstChar,
                             UINT  LastChar,
                             PFLOAT  Buffer)
@@ -429,14 +472,14 @@ W32kGetCharWidthFloat(HDC  hDC,
 
 DWORD
 STDCALL
-W32kGetFontLanguageInfo(HDC  hDC)
+NtGdiGetFontLanguageInfo(HDC  hDC)
 {
   UNIMPLEMENTED;
 }
 
 DWORD
 STDCALL
-W32kGetGlyphOutline(HDC  hDC,
+NtGdiGetGlyphOutline(HDC  hDC,
                            UINT  Char,
                            UINT  Format,
                            LPGLYPHMETRICS  gm,
@@ -451,7 +494,7 @@ W32kGetGlyphOutline(HDC  hDC,
 
 DWORD
 STDCALL
-W32kGetKerningPairs(HDC  hDC,
+NtGdiGetKerningPairs(HDC  hDC,
                            DWORD  NumPairs,
                            LPKERNINGPAIR  krnpair)
 {
@@ -460,7 +503,7 @@ W32kGetKerningPairs(HDC  hDC,
 
 UINT
 STDCALL
-W32kGetOutlineTextMetrics(HDC  hDC,
+NtGdiGetOutlineTextMetrics(HDC  hDC,
                                 UINT  Data,
                                 LPOUTLINETEXTMETRICW  otm)
 {
@@ -469,7 +512,7 @@ W32kGetOutlineTextMetrics(HDC  hDC,
 
 BOOL
 STDCALL
-W32kGetRasterizerCaps(LPRASTERIZER_STATUS  rs,
+NtGdiGetRasterizerCaps(LPRASTERIZER_STATUS  rs,
                             UINT  Size)
 {
   UNIMPLEMENTED;
@@ -477,91 +520,371 @@ W32kGetRasterizerCaps(LPRASTERIZER_STATUS  rs,
 
 UINT
 STDCALL
-W32kGetTextCharset(HDC  hDC)
+NtGdiGetTextCharset(HDC  hDC)
 {
   UNIMPLEMENTED;
 }
 
 UINT
 STDCALL
-W32kGetTextCharsetInfo(HDC  hDC,
+NtGdiGetTextCharsetInfo(HDC  hDC,
                              LPFONTSIGNATURE  Sig,
                              DWORD  Flags)
 {
   UNIMPLEMENTED;
 }
 
-BOOL
-STDCALL
-W32kGetTextExtentExPoint(HDC  hDC,
-                               LPCWSTR String,
-                               int  Count,
-                               int  MaxExtent,
-                               LPINT  Fit,
-                               LPINT  Dx,
-                               LPSIZE  Size)
+static BOOL
+FASTCALL
+TextIntGetTextExtentPoint(PTEXTOBJ TextObj,
+                          LPCWSTR String,
+                          int Count,
+                          int MaxExtent,
+                          LPINT Fit,
+                          LPINT Dx,
+                          LPSIZE Size)
 {
-  UNIMPLEMENTED;
+  PFONTGDI FontGDI;
+  FT_Face face;
+  FT_GlyphSlot glyph;
+  INT error, n, glyph_index, i, previous;
+  LONG TotalWidth = 0, MaxHeight = 0;
+  FT_CharMap charmap, found = NULL;
+  BOOL use_kerning;
+
+  GetFontObjectsFromTextObj(TextObj, NULL, NULL, &FontGDI);
+  face = FontGDI->face;
+  if (NULL != Fit)
+    {
+      *Fit = 0;
+    }
+
+  if (face->charmap == NULL)
+    {
+      DPRINT("WARNING: No charmap selected!\n");
+      DPRINT("This font face has %d charmaps\n", face->num_charmaps);
+
+      for (n = 0; n < face->num_charmaps; n++)
+       {
+         charmap = face->charmaps[n];
+         DPRINT("found charmap encoding: %u\n", charmap->encoding);
+         if (charmap->encoding != 0)
+           {
+             found = charmap;
+             break;
+           }
+       }
+
+      if (! found)
+       {
+         DPRINT1("WARNING: Could not find desired charmap!\n");
+       }
+
+      error = FT_Set_Charmap(face, found);
+      if (error)
+       {
+         DPRINT1("WARNING: Could not set the charmap!\n");
+       }
+    }
+
+  error = FT_Set_Pixel_Sizes(face,
+                             /* FIXME should set character height if neg */
+                             (TextObj->logfont.lfHeight < 0 ?
+                              - TextObj->logfont.lfHeight :
+                              TextObj->logfont.lfHeight),
+                             TextObj->logfont.lfWidth);
+  if (error)
+    {
+      DPRINT1("Error in setting pixel sizes: %u\n", error);
+    }
+
+  use_kerning = FT_HAS_KERNING(face);
+  previous = 0;
+
+  for (i = 0; i < Count; i++)
+    {
+      glyph_index = FT_Get_Char_Index(face, *String);
+      error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
+      if (error)
+       {
+         DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
+       }
+      glyph = face->glyph;
+
+      /* retrieve kerning distance */
+      if (use_kerning && previous && glyph_index)
+       {
+         FT_Vector delta;
+         FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
+         TotalWidth += delta.x >> 6;
+       }
+
+      TotalWidth += glyph->advance.x >> 6;
+      if (glyph->format == ft_glyph_format_outline)
+       {
+         error = FT_Render_Glyph(glyph, ft_render_mode_mono);
+         if (error)
+           {
+             DPRINT1("WARNING: Failed to render glyph!\n");
+           }
+
+         if (0 != glyph->bitmap.rows && MaxHeight < (glyph->bitmap.rows - 1))
+           {
+             MaxHeight = glyph->bitmap.rows - 1;
+           }
+       }
+
+      if (TotalWidth <= MaxExtent && NULL != Fit)
+       {
+         *Fit = i + 1;
+       }
+      if (NULL != Dx)
+       {
+         Dx[i] = TotalWidth;
+       }
+
+      previous = glyph_index;
+      String++;
+    }
+
+  Size->cx = TotalWidth;
+  Size->cy = MaxHeight;
+
+  return TRUE;
 }
 
 BOOL
 STDCALL
-W32kGetTextExtentPoint(HDC  hDC,
-                             LPCWSTR  String,
-                             int  Count,
-                             LPSIZE  Size)
+NtGdiGetTextExtentExPoint(HDC hDC,
+                         LPCWSTR UnsafeString,
+                         int Count,
+                         int MaxExtent,
+                         LPINT UnsafeFit,
+                         LPINT UnsafeDx,
+                         LPSIZE UnsafeSize)
 {
-  PDC dc = (PDC)AccessUserObject((ULONG) hDC);
-  PFONTGDI FontGDI;
-  FT_Face face;
-  FT_GlyphSlot glyph;
-  INT error, pitch, glyph_index, i;
-  ULONG TotalWidth = 0, MaxHeight = 0, CurrentChar = 0, SpaceBetweenChars = 5;
+  PDC dc;
+  LPWSTR String;
+  SIZE Size;
+  NTSTATUS Status;
+  BOOLEAN Result;
+  INT Fit;
+  LPINT Dx;
+  PTEXTOBJ TextObj;
 
-  FontGDI = (PFONTGDI)AccessInternalObject((ULONG) dc->w.hFont);
+  if (Count < 0)
+    {
+      SetLastWin32Error(ERROR_INVALID_PARAMETER);
+      return FALSE;
+    }
+  if (0 == Count)
+    {
+      Size.cx = 0;
+      Size.cy = 0;
+      Status = MmCopyToCaller(UnsafeSize, &Size, sizeof(SIZE));
+      if (! NT_SUCCESS(Status))
+       {
+         SetLastNtError(Status);
+         return FALSE;
+       }
+      return TRUE;
+    }
 
-  for(i=0; i<Count; i++)
-  {
-    glyph_index = FT_Get_Char_Index(face, *String);
-    error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
-    if(error) DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
-    glyph = face->glyph;
+  String = ExAllocatePool(PagedPool, Count * sizeof(WCHAR));
+  if (NULL == String)
+    {
+      SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+      return FALSE;
+    }
 
-    if (glyph->format == ft_glyph_format_outline)
+  if (NULL != UnsafeDx)
     {
-      error = FT_Render_Glyph(glyph, ft_render_mode_mono);
-      if(error) DPRINT1("WARNING: Failed to render glyph!\n");
-      pitch = glyph->bitmap.pitch;
-    } else {
-      pitch = glyph->bitmap.width;
+      Dx = ExAllocatePool(PagedPool, Count * sizeof(INT));
+      if (NULL == Dx)
+       {
+         ExFreePool(String);
+         SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+         return FALSE;
+       }
+    }
+  else
+    {
+      Dx = NULL;
     }
 
-    TotalWidth += pitch-1;
-    if((glyph->bitmap.rows-1) > MaxHeight) MaxHeight = glyph->bitmap.rows-1;
+  Status = MmCopyFromCaller(String, UnsafeString, Count * sizeof(WCHAR));
+  if (! NT_SUCCESS(Status))
+    {
+      if (NULL != Dx)
+       {
+         ExFreePool(Dx);
+       }
+      ExFreePool(String);
+      SetLastNtError(Status);
+      return FALSE;
+    }
 
-    CurrentChar++;
+  dc = DC_LockDc(hDC);
+  if (NULL == dc)
+    {
+      if (NULL != Dx)
+       {
+         ExFreePool(Dx);
+       }
+      ExFreePool(String);
+      SetLastWin32Error(ERROR_INVALID_HANDLE);
+      return FALSE;
+    }
+  TextObj = TEXTOBJ_LockText(dc->w.hFont);
+  DC_UnlockDc(hDC);
+  Result = TextIntGetTextExtentPoint(TextObj, String, Count, MaxExtent,
+                                     NULL == UnsafeFit ? NULL : &Fit, Dx, &Size);
+  TEXTOBJ_UnlockText(dc->w.hFont);
 
-    if(CurrentChar < Size->cx) TotalWidth += SpaceBetweenChars;
-    String++;
-  }
+  ExFreePool(String);
+  if (! Result)
+    {
+      if (NULL != Dx)
+       {
+         ExFreePool(Dx);
+       }
+      return FALSE;
+    }
 
-  Size->cx = TotalWidth;
-  Size->cy = MaxHeight;
+  if (NULL != UnsafeFit)
+    {
+      Status = MmCopyToCaller(UnsafeFit, &Fit, sizeof(INT));
+      if (! NT_SUCCESS(Status))
+       {
+         if (NULL != Dx)
+           {
+             ExFreePool(Dx);
+           }
+         SetLastNtError(Status);
+         return FALSE;
+       }
+    }
+
+  if (NULL != UnsafeDx)
+    {
+      Status = MmCopyToCaller(UnsafeDx, Dx, Count * sizeof(INT));
+      if (! NT_SUCCESS(Status))
+       {
+         if (NULL != Dx)
+           {
+             ExFreePool(Dx);
+           }
+         SetLastNtError(Status);
+         return FALSE;
+       }
+    }
+  if (NULL != Dx)
+    {
+      ExFreePool(Dx);
+    }
+
+  Status = MmCopyToCaller(UnsafeSize, &Size, sizeof(SIZE));
+  if (! NT_SUCCESS(Status))
+    {
+      SetLastNtError(Status);
+      return FALSE;
+    }
+
+  return TRUE;
 }
 
 BOOL
 STDCALL
-W32kGetTextExtentPoint32(HDC  hDC,
-                               LPCWSTR  String,
-                               int  Count,
-                               LPSIZE  Size)
+NtGdiGetTextExtentPoint(HDC hDC,
+                       LPCWSTR String,
+                       int Count,
+                       LPSIZE Size)
 {
-  UNIMPLEMENTED;
+  return NtGdiGetTextExtentExPoint(hDC, String, Count, 0, NULL, NULL, Size);
+}
+
+BOOL
+STDCALL
+NtGdiGetTextExtentPoint32(HDC hDC,
+                         LPCWSTR UnsafeString,
+                         int Count,
+                         LPSIZE UnsafeSize)
+{
+  PDC dc;
+  LPWSTR String;
+  SIZE Size;
+  NTSTATUS Status;
+  BOOLEAN Result;
+  PTEXTOBJ TextObj;
+
+  if (Count < 0)
+    {
+      SetLastWin32Error(ERROR_INVALID_PARAMETER);
+      return FALSE;
+    }
+  if (0 == Count)
+    {
+      Size.cx = 0;
+      Size.cy = 0;
+      Status = MmCopyToCaller(UnsafeSize, &Size, sizeof(SIZE));
+      if (! NT_SUCCESS(Status))
+       {
+         SetLastNtError(Status);
+         return FALSE;
+       }
+      return TRUE;
+    }
+
+  String = ExAllocatePool(PagedPool, Count * sizeof(WCHAR));
+  if (NULL == String)
+    {
+      SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+      return FALSE;
+    }
+
+  Status = MmCopyFromCaller(String, UnsafeString, Count * sizeof(WCHAR));
+  if (! NT_SUCCESS(Status))
+    {
+      ExFreePool(String);
+      SetLastNtError(Status);
+      return FALSE;
+    }
+
+  dc = DC_LockDc(hDC);
+  if (NULL == dc)
+    {
+      ExFreePool(String);
+      SetLastWin32Error(ERROR_INVALID_HANDLE);
+      return FALSE;
+    }
+  TextObj = TEXTOBJ_LockText(dc->w.hFont);
+  DC_UnlockDc(hDC);
+  Result = TextIntGetTextExtentPoint (
+         TextObj, String, Count, 0, NULL, NULL, &Size);
+  dc = DC_LockDc(hDC);
+  ASSERT(dc); // it succeeded earlier, it should now, too
+  TEXTOBJ_UnlockText(dc->w.hFont);
+  DC_UnlockDc(hDC);
+
+  ExFreePool(String);
+  if (! Result)
+    {
+      return FALSE;
+    }
+
+  Status = MmCopyToCaller(UnsafeSize, &Size, sizeof(SIZE));
+  if (! NT_SUCCESS(Status))
+    {
+      SetLastNtError(Status);
+      return FALSE;
+    }
+
+  return TRUE;
 }
 
 int
 STDCALL
-W32kGetTextFace(HDC  hDC,
+NtGdiGetTextFace(HDC  hDC,
                      int  Count,
                      LPWSTR  FaceName)
 {
@@ -570,7 +893,7 @@ W32kGetTextFace(HDC  hDC,
 
 BOOL
 STDCALL
-W32kGetTextMetrics(HDC hDC,
+NtGdiGetTextMetrics(HDC hDC,
                    LPTEXTMETRICW tm)
 {
   PDC dc;
@@ -581,7 +904,7 @@ W32kGetTextMetrics(HDC hDC,
   FT_Face Face;
   ULONG Error;
 
-  dc = DC_HandleToPtr(hDC);
+  dc = DC_LockDc(hDC);
   if (NULL == dc || NULL == tm)
   {
     Status = STATUS_INVALID_PARAMETER;
@@ -595,7 +918,11 @@ W32kGetTextMetrics(HDC hDC,
       if (NT_SUCCESS(Status))
       {
        Face = FontGDI->face;
-       Error = FT_Set_Pixel_Sizes(Face, TextObj->logfont.lfHeight,
+       Error = FT_Set_Pixel_Sizes(Face,
+                                  /* FIXME should set character height if neg */
+                                  (TextObj->logfont.lfHeight < 0 ?
+                                   - TextObj->logfont.lfHeight :
+                                   TextObj->logfont.lfHeight),
                                   TextObj->logfont.lfWidth);
        if (0 != Error)
          {
@@ -606,9 +933,8 @@ W32kGetTextMetrics(HDC hDC,
          {
          memcpy(&SafeTm, &FontGDI->TextMetric, sizeof(TEXTMETRICW));
          SafeTm.tmAscent = (Face->size->metrics.ascender + 32) / 64; // units above baseline
-         SafeTm.tmDescent = (Face->size->metrics.descender + 32) / 64; // units below baseline
-         SafeTm.tmHeight = (Face->size->metrics.ascender +
-                            Face->size->metrics.descender + 32) / 64;
+         SafeTm.tmDescent = (- Face->size->metrics.descender + 32) / 64; // units below baseline
+         SafeTm.tmHeight = SafeTm.tmAscent + SafeTm.tmDescent;
          Status = MmCopyToCaller(tm, &SafeTm, sizeof(TEXTMETRICW));
          }
       }
@@ -619,7 +945,7 @@ W32kGetTextMetrics(HDC hDC,
       ASSERT(FALSE);
       Status = STATUS_INVALID_HANDLE;
     }
-    DC_ReleasePtr(hDC);
+    DC_UnlockDc(hDC);
   }
 
   return NT_SUCCESS(Status);
@@ -627,8 +953,8 @@ W32kGetTextMetrics(HDC hDC,
 
 BOOL
 STDCALL
-W32kPolyTextOut(HDC  hDC,
-                      CONST LPPOLYTEXT  txt,
+NtGdiPolyTextOut(HDC  hDC,
+                      CONST LPPOLYTEXTW  txt,
                       int  Count)
 {
   UNIMPLEMENTED;
@@ -636,14 +962,14 @@ W32kPolyTextOut(HDC  hDC,
 
 BOOL
 STDCALL
-W32kRemoveFontResource(LPCWSTR  FileName)
+NtGdiRemoveFontResource(LPCWSTR  FileName)
 {
   UNIMPLEMENTED;
 }
 
 DWORD
 STDCALL
-W32kSetMapperFlags(HDC  hDC,
+NtGdiSetMapperFlags(HDC  hDC,
                           DWORD  Flag)
 {
   UNIMPLEMENTED;
@@ -651,30 +977,30 @@ W32kSetMapperFlags(HDC  hDC,
 
 UINT
 STDCALL
-W32kSetTextAlign(HDC  hDC,
+NtGdiSetTextAlign(HDC  hDC,
                        UINT  Mode)
 {
   UINT prevAlign;
   DC *dc;
 
-  dc = DC_HandleToPtr(hDC);
+  dc = DC_LockDc(hDC);
   if (!dc)
     {
       return  0;
     }
   prevAlign = dc->w.textAlign;
   dc->w.textAlign = Mode;
-  DC_ReleasePtr( hDC );
+  DC_UnlockDc( hDC );
   return  prevAlign;
 }
 
 COLORREF
 STDCALL
-W32kSetTextColor(HDC hDC,
+NtGdiSetTextColor(HDC hDC,
                  COLORREF color)
 {
   COLORREF  oldColor;
-  PDC  dc = DC_HandleToPtr(hDC);
+  PDC  dc = DC_LockDc(hDC);
 
   if (!dc)
   {
@@ -683,13 +1009,13 @@ W32kSetTextColor(HDC hDC,
 
   oldColor = dc->w.textColor;
   dc->w.textColor = color;
-  DC_ReleasePtr( hDC );
+  DC_UnlockDc( hDC );
   return  oldColor;
 }
 
 BOOL
 STDCALL
-W32kSetTextJustification(HDC  hDC,
+NtGdiSetTextJustification(HDC  hDC,
                                int  BreakExtra,
                                int  BreakCount)
 {
@@ -698,7 +1024,7 @@ W32kSetTextJustification(HDC  hDC,
 
 BOOL
 STDCALL
-W32kTextOut(HDC  hDC,
+NtGdiTextOut(HDC  hDC,
                   int  XStart,
                   int  YStart,
                   LPCWSTR  String,
@@ -706,17 +1032,19 @@ W32kTextOut(HDC  hDC,
 {
   // Fixme: Call EngTextOut, which does the real work (calling DrvTextOut where appropriate)
 
-  DC *dc = DC_HandleToPtr(hDC);
-  SURFOBJ *SurfObj = (SURFOBJ*)AccessUserObject((ULONG) dc->Surface);
+  DC *dc = DC_LockDc(hDC);
+  SURFOBJ *SurfObj;
   int error, glyph_index, n, i;
   FT_Face face;
   FT_GlyphSlot glyph;
-  ULONG TextLeft, TextTop, pitch, previous;
+  ULONG TextLeft, TextTop, pitch, previous, BackgroundLeft;
   FT_Bool use_kerning;
   RECTL DestRect, MaskRect;
   POINTL SourcePoint, BrushOrigin;
-  HBRUSH hBrush = NULL;
-  PBRUSHOBJ Brush = NULL;
+  HBRUSH hBrushFg = NULL;
+  PBRUSHOBJ BrushFg = NULL;
+  HBRUSH hBrushBg = NULL;
+  PBRUSHOBJ BrushBg = NULL;
   HBITMAP HSourceGlyph;
   PSURFOBJ SourceGlyphSurf;
   SIZEL bitSize;
@@ -727,14 +1055,17 @@ W32kTextOut(HDC  hDC,
   PTEXTOBJ TextObj;
   PPALGDI PalDestGDI;
   PXLATEOBJ XlateObj;
+  ULONG Mode;
 
   if( !dc )
        return FALSE;
+  SurfObj = (SURFOBJ*)AccessUserObject((ULONG) dc->Surface);
 
   XStart += dc->w.DCOrgX;
   YStart += dc->w.DCOrgY;
   TextLeft = XStart;
   TextTop = YStart;
+  BackgroundLeft = XStart;
 
   TextObj = TEXTOBJ_LockText(dc->w.hFont);
 
@@ -764,17 +1095,29 @@ W32kTextOut(HDC  hDC,
     if (error) DPRINT1("WARNING: Could not set the charmap!\n");
   }
 
-  error = FT_Set_Pixel_Sizes(face, TextObj->logfont.lfHeight, TextObj->logfont.lfWidth);
+  error = FT_Set_Pixel_Sizes(face,
+                             /* FIXME should set character height if neg */
+                             (TextObj->logfont.lfHeight < 0 ?
+                              - TextObj->logfont.lfHeight :
+                              TextObj->logfont.lfHeight),
+                             TextObj->logfont.lfWidth);
   if(error) {
     DPRINT1("Error in setting pixel sizes: %u\n", error);
        goto fail;
   }
 
-  // Create the brush
-  PalDestGDI = (PPALGDI)AccessInternalObject((ULONG) dc->w.hPalette);
-  XlateObj = (PXLATEOBJ)IntEngCreateXlate(PalDestGDI->Mode, PAL_RGB, dc->w.hPalette, NULL);
-  hBrush = W32kCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, dc->w.textColor));
-  Brush = BRUSHOBJ_LockBrush(hBrush);
+  // Create the brushes
+  PalDestGDI = PALETTE_LockPalette(dc->w.hPalette);
+  Mode = PalDestGDI->Mode;
+  PALETTE_UnlockPalette(dc->w.hPalette);
+  XlateObj = (PXLATEOBJ)IntEngCreateXlate(Mode, PAL_RGB, dc->w.hPalette, NULL);
+  hBrushFg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, dc->w.textColor));
+  BrushFg = BRUSHOBJ_LockBrush(hBrushFg);
+  if (OPAQUE == dc->w.backgroundMode)
+    {
+      hBrushBg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, dc->w.backgroundColor));
+      BrushBg = BRUSHOBJ_LockBrush(hBrushBg);
+    }
   EngDeleteXlate(XlateObj);
 
   SourcePoint.x = 0;
@@ -829,11 +1172,32 @@ W32kTextOut(HDC  hDC,
       pitch = glyph->bitmap.width;
     }
 
+    if (OPAQUE == dc->w.backgroundMode)
+      {
+       DestRect.left = BackgroundLeft;
+       DestRect.right = TextLeft + (glyph->advance.x + 32) / 64;
+       DestRect.top = TextTop + yoff - (face->size->metrics.ascender + 32) / 64;
+       DestRect.bottom = TextTop + yoff + (- face->size->metrics.descender + 32) / 64;
+       IntEngBitBlt(SurfObj,
+                    NULL,
+                    NULL,
+                    dc->CombinedClip,
+                    NULL,
+                    &DestRect,
+                    &SourcePoint,
+                    &SourcePoint,
+                    BrushBg,
+                    &BrushOrigin,
+                    PATCOPY);
+       BackgroundLeft = DestRect.right;
+      }
+
     DestRect.left = TextLeft;
-    DestRect.top = TextTop + yoff - glyph->bitmap_top;
     DestRect.right = TextLeft + glyph->bitmap.width;
+    DestRect.top = TextTop + yoff - glyph->bitmap_top;
     DestRect.bottom = DestRect.top + glyph->bitmap.rows;
-    bitSize.cx = pitch;
+       
+    bitSize.cx = glyph->bitmap.width;
     bitSize.cy = glyph->bitmap.rows;
     MaskRect.right = glyph->bitmap.width;
     MaskRect.bottom = glyph->bitmap.rows;
@@ -845,44 +1209,66 @@ W32kTextOut(HDC  hDC,
     SourceGlyphSurf = (PSURFOBJ)AccessUserObject((ULONG) HSourceGlyph);
 
     // Use the font data as a mask to paint onto the DCs surface using a brush
-    IntEngBitBlt(SurfObj, NULL, SourceGlyphSurf, NULL, NULL, &DestRect, &SourcePoint, &MaskRect, Brush, &BrushOrigin, 0xAACC);
+    IntEngBitBlt (
+               SurfObj,
+               NULL,
+               SourceGlyphSurf,
+               dc->CombinedClip,
+               NULL,
+               &DestRect,
+               &SourcePoint,
+               (PPOINTL)&MaskRect,
+               BrushFg,
+               &BrushOrigin,
+               0xAACC );
 
     EngDeleteSurface(HSourceGlyph);
 
-    TextLeft += glyph->advance.x >> 6;
+    TextLeft += (glyph->advance.x + 32) / 64;
     previous = glyph_index;
 
     String++;
   }
-  TEXTOBJ_UnlockText( dc->w.hFont );
-  BRUSHOBJ_UnlockBrush(hBrush);
-  W32kDeleteObject( hBrush );
-  DC_ReleasePtr( hDC );
+  TEXTOBJ_UnlockText(dc->w.hFont);
+  if (NULL != hBrushBg)
+    {
+      BRUSHOBJ_UnlockBrush(hBrushBg);
+      NtGdiDeleteObject(hBrushBg);
+    }
+  BRUSHOBJ_UnlockBrush(hBrushFg);
+  NtGdiDeleteObject(hBrushFg);
+  DC_UnlockDc(hDC);
   return TRUE;
 
 fail:
   TEXTOBJ_UnlockText( dc->w.hFont );
-  if( hBrush ){
-    BRUSHOBJ_UnlockBrush(hBrush);
-    W32kDeleteObject( hBrush );
-  }
-  DC_ReleasePtr( hDC );
+  if (NULL != hBrushBg)
+    {
+      BRUSHOBJ_UnlockBrush(hBrushBg);
+      NtGdiDeleteObject(hBrushBg);
+    }
+  if (NULL != hBrushFg)
+    {
+      BRUSHOBJ_UnlockBrush(hBrushFg);
+      NtGdiDeleteObject(hBrushFg);
+    }
+  DC_UnlockDc( hDC );
   return FALSE;
 }
 
 UINT
 STDCALL
-W32kTranslateCharsetInfo(PDWORD  Src,
+NtGdiTranslateCharsetInfo(PDWORD  Src,
                                LPCHARSETINFO  CSI,
                                DWORD  Flags)
 {
   UNIMPLEMENTED;
 }
 
-NTSTATUS
+NTSTATUS FASTCALL
 TextIntRealizeFont(HFONT FontHandle)
 {
-  UINT i;
+  LONG i;
   NTSTATUS Status = STATUS_SUCCESS;
   PTEXTOBJ TextObj;
 
@@ -925,3 +1311,5 @@ TextIntRealizeFont(HFONT FontHandle)
 
   return Status;
 }
+
+/* EOF */