Another coordinate transformation change. Fixes final problem with bug 1201.
[reactos.git] / reactos / subsys / win32k / objects / text.c
index 66a5ffd..13fb957 100644 (file)
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-/* $Id: text.c,v 1.107 2004/07/29 12:03:47 weiden Exp $ */
+/* $Id$ */
+
 #include <w32k.h>
 
 #include <ft2build.h>
 #include FT_FREETYPE_H
 #include <freetype/tttables.h>
 
+#define NDEBUG
+#include <debug.h>
+
 FT_Library  library;
 
 typedef struct _FONT_ENTRY {
   LIST_ENTRY ListEntry;
-  HFONT hFont;
+  FONTGDI *Font;
   UNICODE_STRING FaceName;
   BYTE NotEnum;
 } FONT_ENTRY, *PFONT_ENTRY;
@@ -110,7 +114,7 @@ static CHARSETINFO FontTci[MAXTCIINDEX] = {
   { DEFAULT_CHARSET, 0, FS(0)},
   /* reserved for system */
   { DEFAULT_CHARSET, 0, FS(0)},
-  { SYMBOL_CHARSET, CP_SYMBOL, FS(31)},
+  { SYMBOL_CHARSET, 42 /* CP_SYMBOL */, FS(31)},
 };
 
 VOID FASTCALL
@@ -129,8 +133,10 @@ InitFontSupport(VOID)
    ExInitializeFastMutex(&FreeTypeLock);
 
    ulError = FT_Init_FreeType(&library);
-   if (ulError)
+   if (ulError) {
+      DPRINT1("FT_Init_FreeType failed with error code 0x%x\n", ulError);
       return FALSE;
+   }
 
    IntLoadSystemFonts();
 
@@ -155,7 +161,7 @@ IntLoadSystemFonts(VOID)
    BOOL bRestartScan = TRUE;
    NTSTATUS Status;
 
-   RtlInitUnicodeString(&Directory, L"\\SystemRoot\\Media\\Fonts\\");
+   RtlInitUnicodeString(&Directory, L"\\SystemRoot\\media\\fonts\\");
    /* FIXME: Add support for other font types */
    RtlInitUnicodeString(&SearchPattern, L"*.ttf");
 
@@ -182,8 +188,8 @@ IntLoadSystemFonts(VOID)
          ZwClose(hDirectory);
          return;
       }
-      
-      FileName.Buffer = ExAllocatePool(PagedPool, MAX_PATH);
+
+      FileName.Buffer = ExAllocatePool(PagedPool, MAX_PATH * sizeof(WCHAR));
       if (FileName.Buffer == NULL)
       {
          ExFreePool(DirInfoBuffer);
@@ -191,7 +197,7 @@ IntLoadSystemFonts(VOID)
          return;
       }
       FileName.Length = 0;
-      FileName.MaximumLength = MAX_PATH;
+      FileName.MaximumLength = MAX_PATH * sizeof(WCHAR);
 
       while (1)
       {
@@ -213,9 +219,8 @@ IntLoadSystemFonts(VOID)
             break;
          }
 
-         for (DirInfo = (PFILE_DIRECTORY_INFORMATION)DirInfoBuffer;
-              DirInfo->NextEntryOffset != 0;
-              DirInfo = (PFILE_DIRECTORY_INFORMATION)((ULONG_PTR)DirInfo + DirInfo->NextEntryOffset))
+         DirInfo = (PFILE_DIRECTORY_INFORMATION)DirInfoBuffer;
+         while (1)
          {
             TempString.Buffer = DirInfo->FileName;
             TempString.Length =
@@ -223,6 +228,9 @@ IntLoadSystemFonts(VOID)
             RtlCopyUnicodeString(&FileName, &Directory);
             RtlAppendUnicodeStringToString(&FileName, &TempString);
             IntGdiAddFontResource(&FileName, 0);
+            if (DirInfo->NextEntryOffset == 0)
+               break;
+            DirInfo = (PFILE_DIRECTORY_INFORMATION)((ULONG_PTR)DirInfo + DirInfo->NextEntryOffset);
          }
 
          bRestartScan = FALSE;
@@ -243,113 +251,60 @@ IntLoadSystemFonts(VOID)
 INT FASTCALL
 IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
 {
-   HFONT NewFont;
-   FONTOBJ *FontObj;
-   PFONTGDI FontGDI;
+   FONTGDI *FontGDI;
    NTSTATUS Status;
    HANDLE FileHandle;
    OBJECT_ATTRIBUTES ObjectAttributes;
-   FILE_STANDARD_INFORMATION FileStdInfo;
-   PVOID Buffer;
+   PVOID Buffer = NULL;
    IO_STATUS_BLOCK Iosb;
    INT Error;
    FT_Face Face;
    ANSI_STRING AnsiFaceName;
    PFONT_ENTRY Entry;
-
-   /* Create handle for the font */
-
-   NewFont = (HFONT)CreateGDIHandle(
-      sizeof(FONTGDI),
-      sizeof(FONTOBJ),
-      (PVOID*)&FontGDI,
-      (PVOID*)&FontObj);
-
-   if (NewFont == 0)
-   {
-      DPRINT("Could not allocate a new GDI font object\n");
-      return 0;
-   }
+   PSECTION_OBJECT SectionObject;
+   ULONG ViewSize = 0;
 
    /* Open the font file */
 
    InitializeObjectAttributes(&ObjectAttributes, FileName, 0, NULL, NULL);
    Status = ZwOpenFile(
       &FileHandle,
-      GENERIC_READ | SYNCHRONIZE,
+      FILE_GENERIC_READ | SYNCHRONIZE,
       &ObjectAttributes,
       &Iosb,
-      0,
+      FILE_SHARE_READ,
       FILE_SYNCHRONOUS_IO_NONALERT);
 
    if (!NT_SUCCESS(Status))
    {
       DPRINT("Could not font file: %wZ\n", FileName);
-      NtGdiDeleteObject(NewFont);
       return 0;
    }
 
-   /* Get the size of the file */
-
-   Status = NtQueryInformationFile(
-      FileHandle,
-      &Iosb,
-      &FileStdInfo,
-      sizeof(FileStdInfo),
-      FileStandardInformation);
-
+   Status = MmCreateSection(&SectionObject, SECTION_ALL_ACCESS,
+                            NULL, NULL, PAGE_READONLY,
+                            0, FileHandle, NULL);
    if (!NT_SUCCESS(Status))
    {
-      DPRINT("Could not get file size\n");
-      NtGdiDeleteObject(NewFont);
+      DPRINT("Could not map file: %wZ\n", FileName);
       ZwClose(FileHandle);
       return 0;
    }
 
-   /* Allocate pageable memory for the font */
-
-   Buffer = ExAllocatePoolWithTag(
-      PagedPool,
-      FileStdInfo.EndOfFile.u.LowPart,
-      TAG_GDITEXT);
-
-   if (Buffer == NULL)
-   {
-      DPRINT("Could not allocate memory for font");
-      NtGdiDeleteObject(NewFont);
-      ZwClose(FileHandle);
-      return 0;
-   }
-
-   /* Load the font into memory chunk */
-
-   Status = ZwReadFile(
-      FileHandle,
-      NULL,
-      NULL,
-      NULL,
-      &Iosb,
-      Buffer,
-      FileStdInfo.EndOfFile.u.LowPart,
-      NULL,
-      NULL);
+   ZwClose(FileHandle);
 
+   Status = MmMapViewInSystemSpace(SectionObject, &Buffer, &ViewSize);
    if (!NT_SUCCESS(Status))
    {
-      DPRINT("Could not read the font file into memory");
-      ExFreePool(Buffer);
-      NtGdiDeleteObject(NewFont);
-      ZwClose(FileHandle);
-      return 0;
+      DPRINT("Could not map file: %wZ\n", FileName);
+      return Status;
    }
 
-   ZwClose(FileHandle);
-
    IntLockFreeType;
    Error = FT_New_Memory_Face(
       library,
       Buffer,
-      FileStdInfo.EndOfFile.u.LowPart,
+      ViewSize,
       0,
       &Face);
    IntUnLockFreeType;
@@ -360,8 +315,7 @@ IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
          DPRINT("Unknown font file format\n");
       else
          DPRINT("Error reading font file (error code: %u)\n", Error);
-      ExFreePool(Buffer);
-      NtGdiDeleteObject(NewFont);
+      ObDereferenceObject(SectionObject);
       return 0;
    }
 
@@ -369,7 +323,17 @@ IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
    if (!Entry)
    {
       FT_Done_Face(Face);
-      ExFreePool(Buffer);
+      ObDereferenceObject(SectionObject);
+      SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+      return 0;
+   }
+
+   FontGDI = EngAllocMem(FL_ZERO_MEMORY, sizeof(FONTGDI), TAG_FONTOBJ);
+   if(FontGDI == NULL)
+   {
+      FT_Done_Face(Face);
+      ObDereferenceObject(SectionObject);
+      ExFreePool(Entry);
       SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
       return 0;
    }
@@ -380,14 +344,15 @@ IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
    /* FIXME: Complete text metrics */
    FontGDI->TextMetric.tmAscent = (Face->size->metrics.ascender + 32) >> 6; /* units above baseline */
    FontGDI->TextMetric.tmDescent = (32 - Face->size->metrics.descender) >> 6; /* units below baseline */
-   FontGDI->TextMetric.tmHeight = FontGDI->TextMetric.tmAscent + FontGDI->TextMetric.tmDescent;
+   FontGDI->TextMetric.tmHeight = (Face->size->metrics.ascender -
+                                   Face->size->metrics.descender) >> 6;
 
    DPRINT("Font loaded: %s (%s)\n", Face->family_name, Face->style_name);
    DPRINT("Num glyphs: %u\n", Face->num_glyphs);
 
    /* Add this font resource to the font table */
 
-   Entry->hFont = NewFont;
+   Entry->Font = FontGDI;
    Entry->NotEnum = (Characteristics & FR_NOT_ENUM);
    RtlInitAnsiString(&AnsiFaceName, (LPSTR)Face->family_name);
    RtlAnsiStringToUnicodeString(&Entry->FaceName, &AnsiFaceName, TRUE);
@@ -430,54 +395,17 @@ IntEnableFontRendering(BOOL Enable)
 
 FT_Render_Mode FASTCALL
 IntGetFontRenderMode(LOGFONTW *logfont)
-{  
+{
   switch(logfont->lfQuality)
   {
-    //case ANTIALIASED_QUALITY:
-    case DEFAULT_QUALITY:
-      return FT_RENDER_MODE_NORMAL;
+    case NONANTIALIASED_QUALITY:
+      return FT_RENDER_MODE_MONO;
     case DRAFT_QUALITY:
       return FT_RENDER_MODE_LIGHT;
-    //case NONANTIALIASED_QUALITY:
-    case PROOF_QUALITY:
-      return FT_RENDER_MODE_MONO;
-    //case CLEARTYPE_QUALITY:
-    //  return FT_RENDER_MODE_LCD;
-  }
-  return FT_RENDER_MODE_MONO;
-}
-static NTSTATUS STDCALL
-GetFontObjectsFromTextObj(PTEXTOBJ TextObj, HFONT *FontHandle, FONTOBJ **FontObj, PFONTGDI *FontGDI)
-{
-  FONTOBJ *FntObj;
-  NTSTATUS Status = STATUS_SUCCESS;
-
-  ASSERT(NULL != TextObj && NULL != TextObj->GDIFontHandle);
-  if (NULL != TextObj && NULL != TextObj->GDIFontHandle)
-  {
-    if (NULL != FontHandle)
-    {
-      *FontHandle = TextObj->GDIFontHandle;
-    }
-    FntObj = (FONTOBJ*)AccessUserObject((ULONG) TextObj->GDIFontHandle);
-    if (NULL != FontObj)
-    {
-      *FontObj = FntObj;
-      if (NULL == *FontObj)
-      {
-       ASSERT(FALSE);
-       Status = STATUS_INVALID_HANDLE;
-      }
-    }
-    if (NT_SUCCESS(Status) && NULL != FontGDI)
-    {
-      *FontGDI = AccessInternalObjectFromUserObject(FntObj);
-    }
-    
-    return Status;
+/*    case CLEARTYPE_QUALITY:
+        return FT_RENDER_MODE_LCD; */
   }
-  
-  return STATUS_INVALID_HANDLE;
+  return FT_RENDER_MODE_NORMAL;
 }
 
 int
@@ -488,7 +416,7 @@ NtGdiAddFontResource(PUNICODE_STRING Filename, DWORD fl)
   PWSTR src;
   NTSTATUS Status;
   int Ret;
-  
+
   /* Copy the UNICODE_STRING structure */
   Status = MmCopyFromCaller(&SafeFileName, Filename, sizeof(UNICODE_STRING));
   if(!NT_SUCCESS(Status))
@@ -500,7 +428,7 @@ NtGdiAddFontResource(PUNICODE_STRING Filename, DWORD fl)
   /* Reserve for prepending '\??\' */
   SafeFileName.Length += 4 * sizeof(WCHAR);
   SafeFileName.MaximumLength += 4 * sizeof(WCHAR);
-  
+
   src = SafeFileName.Buffer;
   SafeFileName.Buffer = (PWSTR)ExAllocatePoolWithTag(PagedPool, SafeFileName.MaximumLength, TAG_STRING);
   if(!SafeFileName.Buffer)
@@ -508,7 +436,7 @@ NtGdiAddFontResource(PUNICODE_STRING Filename, DWORD fl)
     SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
     return 0;
   }
-  
+
   /* Prepend '\??\' */
   RtlCopyMemory(SafeFileName.Buffer, L"\\??\\", 4 * sizeof(WCHAR));
 
@@ -519,9 +447,9 @@ NtGdiAddFontResource(PUNICODE_STRING Filename, DWORD fl)
     SetLastNtError(Status);
     return 0;
   }
-  
+
   Ret = IntGdiAddFontResource(&SafeFileName, fl);
-  
+
   ExFreePool(SafeFileName.Buffer);
   return Ret;
 }
@@ -544,13 +472,13 @@ TextIntCreateFontIndirect(CONST LPLOGFONTW lf, HFONT *NewFont)
        /* this should really depend on whether GM_ADVANCED is set */
        TextObj->logfont.lfOrientation = TextObj->logfont.lfEscapement;
       }
-      TEXTOBJ_UnlockText(*NewFont);
+      TEXTOBJ_UnlockText(TextObj);
     }
     else
     {
 /* FIXME */
 /*      ASSERT(FALSE);*/
-      Status = STATUS_INVALID_HANDLE;      
+      Status = STATUS_INVALID_HANDLE;
     }
   }
   else
@@ -647,7 +575,7 @@ NtGdiCreateScalableFontResource(DWORD  Hidden,
                                      LPCWSTR  FontFile,
                                      LPCWSTR  CurrentPath)
 {
-  UNIMPLEMENTED;
+       DPRINT1("NtGdiCreateScalableFontResource - is unimplemented, have a nice day and keep going");
   return FALSE;
 }
 
@@ -733,91 +661,14 @@ NtGdiTranslateCharsetInfo(PDWORD Src,
   return (BOOL) Ret;
 }
 
-
-/*************************************************************
- * IntGetOutlineTextMetrics
- *
- */
-static unsigned FASTCALL
-IntGetOutlineTextMetrics(PFONTGDI FontGDI, UINT Size,
-                         OUTLINETEXTMETRICW *Otm)
+static void FASTCALL
+FillTM(TEXTMETRICW *TM, FT_Face Face, TT_OS2 *pOS2, TT_HoriHeader *pHori)
 {
-  unsigned Needed;
-  TT_OS2 *pOS2;
-  TT_HoriHeader *pHori;
-  TT_Postscript *pPost;
   FT_Fixed XScale, YScale;
-  ANSI_STRING FamilyNameA, StyleNameA;
-  UNICODE_STRING FamilyNameW, StyleNameW, Regular;
-  char *Cp;
   int Ascent, Descent;
-  TEXTMETRICW *TM;
 
-  Needed = sizeof(OUTLINETEXTMETRICW);
-
-  RtlInitAnsiString(&FamilyNameA, FontGDI->face->family_name);
-  RtlAnsiStringToUnicodeString(&FamilyNameW, &FamilyNameA, TRUE);
-
-  RtlInitAnsiString(&StyleNameA, FontGDI->face->style_name);
-  RtlAnsiStringToUnicodeString(&StyleNameW, &StyleNameA, TRUE);
-
-  /* These names should be read from the TT name table */
-
-  /* length of otmpFamilyName */
-  Needed += FamilyNameW.Length + sizeof(WCHAR);
-
-  RtlInitUnicodeString(&Regular, L"regular");
-  /* length of otmpFaceName */
-  if (0 == RtlCompareUnicodeString(&StyleNameW, &Regular, TRUE))
-    {
-      Needed += FamilyNameW.Length + sizeof(WCHAR); /* just the family name */
-    }
-  else
-    {
-      Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1); /* family + " " + style */
-    }
-
-  /* length of otmpStyleName */
-  Needed += StyleNameW.Length + sizeof(WCHAR);
-
-  /* length of otmpFullName */
-  Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1);
-
-  if (Size < Needed)
-    {
-      RtlFreeUnicodeString(&FamilyNameW);
-      RtlFreeUnicodeString(&StyleNameW);
-      return Needed;
-    }
-
-  XScale = FontGDI->face->size->metrics.x_scale;
-  YScale = FontGDI->face->size->metrics.y_scale;
-
-  IntLockFreeType;
-  pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2);
-  if (NULL == pOS2)
-    {
-      IntUnLockFreeType;
-      DPRINT1("Can't find OS/2 table - not TT font?\n");
-      RtlFreeUnicodeString(&StyleNameW);
-      RtlFreeUnicodeString(&FamilyNameW);
-      return 0;
-    }
-
-  pHori = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_hhea);
-  if (NULL == pHori)
-    {
-      IntUnLockFreeType;
-      DPRINT1("Can't find HHEA table - not TT font?\n");
-      RtlFreeUnicodeString(&StyleNameW);
-      RtlFreeUnicodeString(&FamilyNameW);
-      return 0;
-    }
-
-  pPost = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_post); /* we can live with this failing */
-  IntUnLockFreeType;
-
-  Otm->otmSize = Needed;
+  XScale = Face->size->metrics.x_scale;
+  YScale = Face->size->metrics.y_scale;
 
   if (0 == pOS2->usWinAscent + pOS2->usWinDescent)
     {
@@ -830,11 +681,15 @@ IntGetOutlineTextMetrics(PFONTGDI FontGDI, UINT Size,
       Descent = pOS2->usWinDescent;
     }
 
-  TM = &Otm->otmTextMetrics;
+#if 0 /* This (Wine) code doesn't seem to work correctly for us */
   TM->tmAscent = (FT_MulFix(Ascent, YScale) + 32) >> 6;
   TM->tmDescent = (FT_MulFix(Descent, YScale) + 32) >> 6;
+#else
+  TM->tmAscent = (Face->size->metrics.ascender + 32) >> 6; /* units above baseline */
+  TM->tmDescent = (32 - Face->size->metrics.descender) >> 6; /* units below baseline */
+#endif
   TM->tmInternalLeading = (FT_MulFix(Ascent + Descent
-                                     - FontGDI->face->units_per_EM, YScale) + 32) >> 6;
+                                     - Face->units_per_EM, YScale) + 32) >> 6;
 
   TM->tmHeight = TM->tmAscent + TM->tmDescent;
 
@@ -849,10 +704,10 @@ IntGetOutlineTextMetrics(PFONTGDI FontGDI, UINT Size,
   TM->tmAveCharWidth = (FT_MulFix(pOS2->xAvgCharWidth, XScale) + 32) >> 6;
   if (0 == TM->tmAveCharWidth)
     {
-      TM->tmAveCharWidth = 1; 
+      TM->tmAveCharWidth = 1;
     }
-  TM->tmMaxCharWidth = (FT_MulFix(FontGDI->face->bbox.xMax - FontGDI->face->bbox.xMin,
-                                 XScale) + 32) >> 6;
+  TM->tmMaxCharWidth = (FT_MulFix(Face->bbox.xMax - Face->bbox.xMin,
+                                  XScale) + 32) >> 6;
   TM->tmWeight = pOS2->usWeightClass;
   TM->tmOverhang = 0;
   TM->tmDigitizedAspectX = 300;
@@ -861,12 +716,12 @@ IntGetOutlineTextMetrics(PFONTGDI FontGDI, UINT Size,
   TM->tmLastChar = pOS2->usLastCharIndex;
   TM->tmDefaultChar = pOS2->usDefaultChar;
   TM->tmBreakChar = L'\0' != pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
-  TM->tmItalic = (FontGDI->face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0;
+  TM->tmItalic = (Face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0;
   TM->tmUnderlined = 0; /* entry in OS2 table */
   TM->tmStruckOut = 0; /* entry in OS2 table */
 
   /* Yes TPMF_FIXED_PITCH is correct; braindead api */
-  if (! FT_IS_FIXED_WIDTH(FontGDI->face))
+  if (! FT_IS_FIXED_WIDTH(Face))
     {
       TM->tmPitchAndFamily = TMPF_FIXED_PITCH;
     }
@@ -908,18 +763,101 @@ IntGetOutlineTextMetrics(PFONTGDI FontGDI, UINT Size,
         TM->tmPitchAndFamily |= FF_DONTCARE;
     }
 
-  if (FT_IS_SCALABLE(FontGDI->face))
+  if (FT_IS_SCALABLE(Face))
     {
       TM->tmPitchAndFamily |= TMPF_VECTOR;
     }
-  if (FT_IS_SFNT(FontGDI->face))
+  if (FT_IS_SFNT(Face))
     {
       TM->tmPitchAndFamily |= TMPF_TRUETYPE;
     }
 
-#ifndef TODO
   TM->tmCharSet = DEFAULT_CHARSET;
-#endif
+}
+
+/*************************************************************
+ * IntGetOutlineTextMetrics
+ *
+ */
+static unsigned FASTCALL
+IntGetOutlineTextMetrics(PFONTGDI FontGDI, UINT Size,
+                         OUTLINETEXTMETRICW *Otm)
+{
+  unsigned Needed;
+  TT_OS2 *pOS2;
+  TT_HoriHeader *pHori;
+  TT_Postscript *pPost;
+  FT_Fixed XScale, YScale;
+  ANSI_STRING FamilyNameA, StyleNameA;
+  UNICODE_STRING FamilyNameW, StyleNameW, Regular;
+  char *Cp;
+
+  Needed = sizeof(OUTLINETEXTMETRICW);
+
+  RtlInitAnsiString(&FamilyNameA, FontGDI->face->family_name);
+  RtlAnsiStringToUnicodeString(&FamilyNameW, &FamilyNameA, TRUE);
+
+  RtlInitAnsiString(&StyleNameA, FontGDI->face->style_name);
+  RtlAnsiStringToUnicodeString(&StyleNameW, &StyleNameA, TRUE);
+
+  /* These names should be read from the TT name table */
+
+  /* length of otmpFamilyName */
+  Needed += FamilyNameW.Length + sizeof(WCHAR);
+
+  RtlInitUnicodeString(&Regular, L"regular");
+  /* length of otmpFaceName */
+  if (0 == RtlCompareUnicodeString(&StyleNameW, &Regular, TRUE))
+    {
+      Needed += FamilyNameW.Length + sizeof(WCHAR); /* just the family name */
+    }
+  else
+    {
+      Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1); /* family + " " + style */
+    }
+
+  /* length of otmpStyleName */
+  Needed += StyleNameW.Length + sizeof(WCHAR);
+
+  /* length of otmpFullName */
+  Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1);
+
+  if (Size < Needed)
+    {
+      RtlFreeUnicodeString(&FamilyNameW);
+      RtlFreeUnicodeString(&StyleNameW);
+      return Needed;
+    }
+
+  XScale = FontGDI->face->size->metrics.x_scale;
+  YScale = FontGDI->face->size->metrics.y_scale;
+
+  IntLockFreeType;
+  pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2);
+  if (NULL == pOS2)
+    {
+      IntUnLockFreeType;
+      DPRINT1("Can't find OS/2 table - not TT font?\n");
+      RtlFreeUnicodeString(&StyleNameW);
+      RtlFreeUnicodeString(&FamilyNameW);
+      return 0;
+    }
+
+  pHori = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_hhea);
+  if (NULL == pHori)
+    {
+      IntUnLockFreeType;
+      DPRINT1("Can't find HHEA table - not TT font?\n");
+      RtlFreeUnicodeString(&StyleNameW);
+      RtlFreeUnicodeString(&FamilyNameW);
+      return 0;
+    }
+
+  pPost = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_post); /* we can live with this failing */
+
+  Otm->otmSize = Needed;
+
+  FillTM(&Otm->otmTextMetrics, FontGDI->face, pOS2, pHori);
 
   Otm->otmFiller = 0;
   memcpy(&Otm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
@@ -963,6 +901,8 @@ IntGetOutlineTextMetrics(PFONTGDI FontGDI, UINT Size,
       Otm->otmsUnderscorePosition = (FT_MulFix(pPost->underlinePosition, YScale) + 32) >> 6;
     }
 
+  IntUnLockFreeType;
+
   /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
   Cp = (char*) Otm + sizeof(OUTLINETEXTMETRICW);
   Otm->otmpFamilyName = (LPSTR)(Cp - (char*) Otm);
@@ -1001,18 +941,16 @@ FindFaceNameInList(PUNICODE_STRING FaceName, PLIST_ENTRY Head)
   PFONT_ENTRY CurrentEntry;
   ANSI_STRING EntryFaceNameA;
   UNICODE_STRING EntryFaceNameW;
-  PFONTGDI FontGDI;
+  FONTGDI *FontGDI;
 
   Entry = Head->Flink;
   while (Entry != Head)
     {
       CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
 
-      if (NULL == (FontGDI = AccessInternalObject((ULONG) CurrentEntry->hFont)))
-        {
-          Entry = Entry->Flink;
-          continue;
-        }
+      FontGDI = CurrentEntry->Font;
+      ASSERT(FontGDI);
+
       RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name);
       RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
       if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
@@ -1072,8 +1010,8 @@ FontFamilyFillInfo(PFONTFAMILYINFO Info, PCWSTR FaceName, PFONTGDI FontGDI)
   LOGFONTW *Lf;
   TEXTMETRICW *TM;
   NEWTEXTMETRICW *Ntm;
-  
-  ZeroMemory(Info, sizeof(FONTFAMILYINFO));
+
+  RtlZeroMemory(Info, sizeof(FONTFAMILYINFO));
   Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
   Otm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
   if (NULL == Otm)
@@ -1164,7 +1102,7 @@ FontFamilyFillInfo(PFONTFAMILYINFO Info, PCWSTR FaceName, PFONTGDI FontGDI)
       if (0 == pOS2->version)
         {
           FT_UInt Dummy;
-       
+
           if (FT_Get_First_Char(FontGDI->face, &Dummy) < 0x100)
             {
               fs_fsCsb0 |= 1;
@@ -1269,18 +1207,16 @@ GetFontFamilyInfoForList(LPLOGFONTW LogFont,
   PFONT_ENTRY CurrentEntry;
   ANSI_STRING EntryFaceNameA;
   UNICODE_STRING EntryFaceNameW;
-  PFONTGDI FontGDI;
+  FONTGDI *FontGDI;
 
   Entry = Head->Flink;
   while (Entry != Head)
     {
       CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
 
-      if (NULL == (FontGDI = AccessInternalObject((ULONG) CurrentEntry->hFont)))
-        {
-          Entry = Entry->Flink;
-          continue;
-        }
+      FontGDI = CurrentEntry->Font;
+      ASSERT(FontGDI);
+
       RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name);
       RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
       if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
@@ -1453,7 +1389,7 @@ NtGdiGetFontFamilyInfo(HDC Dc,
   /* Enumerate font families in the process local list */
   Win32Process = PsGetWin32Process();
   IntLockProcessPrivateFonts(Win32Process);
-  if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, 
+  if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size,
                                  &Win32Process->PrivateFontListHead))
     {
       IntUnLockProcessPrivateFonts(Win32Process);
@@ -1517,13 +1453,14 @@ NtGdiExtTextOut(
 
    DC *dc;
    SURFOBJ *SurfObj;
-   BITMAPOBJ *BitmapObj;
+   BITMAPOBJ *BitmapObj = NULL;
    int error, glyph_index, n, i;
    FT_Face face;
    FT_GlyphSlot glyph;
-   ULONG TextLeft, TextTop, pitch, previous, BackgroundLeft;
+   LONGLONG TextLeft, RealXStart;
+   ULONG TextTop, previous, BackgroundLeft;
    FT_Bool use_kerning;
-   RECTL DestRect, MaskRect;
+   RECTL DestRect, MaskRect, SpecifiedDestRect;
    POINTL SourcePoint, BrushOrigin;
    HBRUSH hBrushFg = NULL;
    PGDIBRUSHOBJ BrushFg = NULL;
@@ -1538,23 +1475,44 @@ NtGdiExtTextOut(
    INT yoff;
    FONTOBJ *FontObj;
    PFONTGDI FontGDI;
-   PTEXTOBJ TextObj;
+   PTEXTOBJ TextObj = NULL;
    PPALGDI PalDestGDI;
-   XLATEOBJ *XlateObj, *XlateObj2;
+   XLATEOBJ *XlateObj=NULL, *XlateObj2=NULL;
    ULONG Mode;
    FT_Render_Mode RenderMode;
    BOOLEAN Render;
    NTSTATUS Status;
    INT *Dx = NULL;
    POINT Start;
+   BOOL DoBreak = FALSE;
 
+   // TODO: Write test-cases to exactly match real Windows in different
+   // bad parameters (e.g. does Windows check the DC or the RECT first?).
    dc = DC_LockDc(hDC);
    if (!dc)
    {
       SetLastWin32Error(ERROR_INVALID_HANDLE);
       return FALSE;
    }
-   
+   if (dc->IsIC)
+   {
+      DC_UnlockDc(dc);
+      /* Yes, Windows really returns TRUE in this case */
+      return TRUE;
+   }
+
+   if (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED)))
+   {
+      // At least one of the two flags were specified. Copy lprc. Once.
+      Status = MmCopyFromCaller(&SpecifiedDestRect, lprc, sizeof(RECT));
+      if (!NT_SUCCESS(Status))
+      {
+         SetLastWin32Error(ERROR_INVALID_PARAMETER);
+         return FALSE;
+      }
+      IntLPtoDP(dc, (POINT *) &SpecifiedDestRect, 2);
+   }
+
    if (NULL != UnsafeDx && Count > 0)
    {
       Dx = ExAllocatePoolWithTag(PagedPool, Count * sizeof(INT), TAG_GDITEXT);
@@ -1568,46 +1526,66 @@ NtGdiExtTextOut(
          goto fail;
       }
    }
+
    BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
-   ASSERT(BitmapObj);
+   if ( !BitmapObj )
+   {
+      goto fail;
+   }
    SurfObj = &BitmapObj->SurfObj;
+   ASSERT(SurfObj);
 
    Start.x = XStart; Start.y = YStart;
    IntLPtoDP(dc, &Start, 1);
 
-   XStart = Start.x + dc->w.DCOrgX;
+   RealXStart = (Start.x + dc->w.DCOrgX) << 6;
    YStart = Start.y + dc->w.DCOrgY;
 
    /* Create the brushes */
    PalDestGDI = PALETTE_LockPalette(dc->w.hPalette);
    if ( !PalDestGDI )
-          Mode = PAL_RGB;
+      Mode = PAL_RGB;
    else
    {
-          Mode = PalDestGDI->Mode;
-          PALETTE_UnlockPalette(dc->w.hPalette);
+      Mode = PalDestGDI->Mode;
+      PALETTE_UnlockPalette(PalDestGDI);
    }
    XlateObj = (XLATEOBJ*)IntEngCreateXlate(Mode, PAL_RGB, dc->w.hPalette, NULL);
-   hBrushFg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, dc->w.textColor));
+   if ( !XlateObj )
+   {
+      goto fail;
+   }
+   hBrushFg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, dc->w.textColor), 0);
+   if ( !hBrushFg )
+   {
+      goto fail;
+   }
    BrushFg = BRUSHOBJ_LockBrush(hBrushFg);
+   if ( !BrushFg )
+   {
+      goto fail;
+   }
    IntGdiInitBrushInstance(&BrushFgInst, BrushFg, NULL);
    if ((fuOptions & ETO_OPAQUE) || dc->w.backgroundMode == OPAQUE)
    {
-      hBrushBg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, dc->w.backgroundColor));
-      if (hBrushBg)
+      hBrushBg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, dc->w.backgroundColor), 0);
+      if ( !hBrushBg )
       {
-         BrushBg = BRUSHOBJ_LockBrush(hBrushBg);
-         IntGdiInitBrushInstance(&BrushBgInst, BrushBg, NULL);
+         goto fail;
       }
-      else
+      BrushBg = BRUSHOBJ_LockBrush(hBrushBg);
+      if ( !BrushBg )
       {
-         EngDeleteXlate(XlateObj);
          goto fail;
       }
+      IntGdiInitBrushInstance(&BrushBgInst, BrushBg, NULL);
    }
    XlateObj2 = (XLATEOBJ*)IntEngCreateXlate(PAL_RGB, Mode, NULL, dc->w.hPalette);
-  
+   if ( !XlateObj2 )
+   {
+      goto fail;
+   }
+
    SourcePoint.x = 0;
    SourcePoint.y = 0;
    MaskRect.left = 0;
@@ -1617,13 +1595,13 @@ NtGdiExtTextOut(
 
    if ((fuOptions & ETO_OPAQUE) && lprc)
    {
-      MmCopyFromCaller(&DestRect, lprc, sizeof(RECT));
-      DestRect.left += dc->w.DCOrgX;
-      DestRect.top += dc->w.DCOrgY;
-      DestRect.right += dc->w.DCOrgX;
-      DestRect.bottom += dc->w.DCOrgY;
+      DestRect.left   = SpecifiedDestRect.left   + dc->w.DCOrgX;
+      DestRect.top    = SpecifiedDestRect.top    + dc->w.DCOrgY;
+      DestRect.right  = SpecifiedDestRect.right  + dc->w.DCOrgX;
+      DestRect.bottom = SpecifiedDestRect.bottom + dc->w.DCOrgY;
+      IntLPtoDP(dc, (LPPOINT)&DestRect, 2);
       IntEngBitBlt(
-         BitmapObj,
+         &BitmapObj->SurfObj,
          NULL,
          NULL,
          dc->CombinedClip,
@@ -1633,7 +1611,7 @@ NtGdiExtTextOut(
          &SourcePoint,
          &BrushBgInst.BrushObject,
          &BrushOrigin,
-         PATCOPY);
+         ROP3_TO_ROP4(PATCOPY));
       fuOptions &= ~ETO_OPAQUE;
    }
    else
@@ -1645,12 +1623,17 @@ NtGdiExtTextOut(
    }
 
    TextObj = TEXTOBJ_LockText(dc->w.hFont);
-
-   if (!NT_SUCCESS(GetFontObjectsFromTextObj(TextObj, NULL, &FontObj, &FontGDI)))
+   if(TextObj == NULL)
    {
       goto fail;
    }
 
+   FontObj = TextObj->Font;
+   ASSERT(FontObj);
+   FontGDI = ObjToGDI(FontObj, FONT);
+   ASSERT(FontGDI);
+
+   IntLockFreeType;
    face = FontGDI->face;
    if (face->charmap == NULL)
    {
@@ -1668,12 +1651,14 @@ NtGdiExtTextOut(
          }
       }
       if (!found)
+      {
          DPRINT1("WARNING: Could not find desired charmap!\n");
-      IntLockFreeType;
+      }
       error = FT_Set_Charmap(face, found);
-      IntUnLockFreeType;
-      if (error)
+         if (error)
+      {
          DPRINT1("WARNING: Could not set the charmap!\n");
+      }
    }
 
    Render = IntIsFontRenderingEnabled();
@@ -1681,19 +1666,18 @@ NtGdiExtTextOut(
       RenderMode = IntGetFontRenderMode(&TextObj->logfont);
    else
       RenderMode = FT_RENDER_MODE_MONO;
-  
-   IntLockFreeType;
+
    error = FT_Set_Pixel_Sizes(
       face,
+      TextObj->logfont.lfWidth,
       /* FIXME should set character height if neg */
       (TextObj->logfont.lfHeight < 0 ?
       - TextObj->logfont.lfHeight :
-      TextObj->logfont.lfHeight),
-      TextObj->logfont.lfWidth);
-   IntUnLockFreeType;
+      TextObj->logfont.lfHeight == 0 ? 11 : TextObj->logfont.lfHeight));
    if (error)
    {
       DPRINT1("Error in setting pixel sizes: %u\n", error);
+      IntUnLockFreeType;
       goto fail;
    }
 
@@ -1717,7 +1701,7 @@ NtGdiExtTextOut(
 
    if (dc->w.textAlign & (TA_RIGHT | TA_CENTER))
    {
-      UINT TextWidth = 0;
+      ULONGLONG TextWidth = 0;
       LPCWSTR TempText = String;
       int Start;
 
@@ -1728,7 +1712,7 @@ NtGdiExtTextOut(
       if (NULL != Dx)
       {
          Start = Count < 2 ? 0 : Count - 2;
-         TextWidth = Count < 2 ? 0 : Dx[Count - 2];
+         TextWidth = Count < 2 ? 0 : (Dx[Count - 2] << 6);
       }
       else
       {
@@ -1738,11 +1722,9 @@ NtGdiExtTextOut(
 
       for (i = Start; i < Count; i++)
       {
-         IntLockFreeType;
          glyph_index = FT_Get_Char_Index(face, *TempText);
          error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
-         IntUnLockFreeType;
-      
+
          if (error)
          {
             DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
@@ -1754,13 +1736,11 @@ NtGdiExtTextOut(
          if (use_kerning && previous && glyph_index)
          {
             FT_Vector delta;
-            IntLockFreeType;
             FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
-            IntUnLockFreeType;
-            TextWidth += delta.x >> 6;
+            TextWidth += delta.x;
          }
 
-         TextWidth += glyph->advance.x >> 6;
+         TextWidth += glyph->advance.x;
 
          previous = glyph_index;
          TempText++;
@@ -1770,17 +1750,17 @@ NtGdiExtTextOut(
 
       if (dc->w.textAlign & TA_RIGHT)
       {
-         XStart -= TextWidth;
+         RealXStart -= TextWidth;
       }
       else
       {
-         XStart -= TextWidth / 2;
+         RealXStart -= TextWidth / 2;
       }
    }
 
-   TextLeft = XStart;
+   TextLeft = RealXStart;
    TextTop = YStart;
-   BackgroundLeft = XStart;
+   BackgroundLeft = (RealXStart + 32) >> 6;
 
    /*
     * The main rendering loop.
@@ -1788,16 +1768,13 @@ NtGdiExtTextOut(
 
    for (i = 0; i < Count; i++)
    {
-      IntLockFreeType;
       glyph_index = FT_Get_Char_Index(face, *String);
       error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
-      IntUnLockFreeType;
 
       if (error)
       {
-         EngDeleteXlate(XlateObj);
-         EngDeleteXlate(XlateObj2);
          DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
+        IntUnLockFreeType;
          goto fail;
       }
 
@@ -1807,37 +1784,28 @@ NtGdiExtTextOut(
       if (use_kerning && previous && glyph_index && NULL == Dx)
       {
          FT_Vector delta;
-         IntLockFreeType;
          FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
-         IntUnLockFreeType;
-         TextLeft += delta.x >> 6;
+         TextLeft += delta.x;
       }
 
       if (glyph->format == ft_glyph_format_outline)
       {
-         IntLockFreeType;
          error = FT_Render_Glyph(glyph, RenderMode);
-         IntUnLockFreeType;
          if (error)
          {
-            EngDeleteXlate(XlateObj);
-            EngDeleteXlate(XlateObj2);
             DPRINT1("WARNING: Failed to render glyph!\n");
             goto fail;
          }
-         pitch = glyph->bitmap.pitch;
-      } else {
-         pitch = glyph->bitmap.width;
       }
 
       if (fuOptions & ETO_OPAQUE)
       {
          DestRect.left = BackgroundLeft;
-         DestRect.right = TextLeft + ((glyph->advance.x + 32) >> 6);
+         DestRect.right = (TextLeft + glyph->advance.x + 32) >> 6;
          DestRect.top = TextTop + yoff - ((face->size->metrics.ascender + 32) >> 6);
          DestRect.bottom = TextTop + yoff + ((32 - face->size->metrics.descender) >> 6);
          IntEngBitBlt(
-            BitmapObj,
+            &BitmapObj->SurfObj,
             NULL,
             NULL,
             dc->CombinedClip,
@@ -1847,34 +1815,66 @@ NtGdiExtTextOut(
             &SourcePoint,
             &BrushBgInst.BrushObject,
             &BrushOrigin,
-            PATCOPY);
+            ROP3_TO_ROP4(PATCOPY));
          BackgroundLeft = DestRect.right;
       }
 
-      DestRect.left = TextLeft;
-      DestRect.right = TextLeft + glyph->bitmap.width;
+      DestRect.left = ((TextLeft + 32) >> 6) + glyph->bitmap_left;
+      DestRect.right = DestRect.left + glyph->bitmap.width;
       DestRect.top = TextTop + yoff - glyph->bitmap_top;
       DestRect.bottom = DestRect.top + glyph->bitmap.rows;
-       
+
       bitSize.cx = glyph->bitmap.width;
       bitSize.cy = glyph->bitmap.rows;
       MaskRect.right = glyph->bitmap.width;
       MaskRect.bottom = glyph->bitmap.rows;
-    
+
       /*
        * We should create the bitmap out of the loop at the biggest possible
        * glyph size. Then use memset with 0 to clear it and sourcerect to
        * limit the work of the transbitblt.
+       *
+       * FIXME: DIB bitmaps should have an lDelta which is a multiple of 4.
+       * Here we pass in the pitch from the FreeType bitmap, which is not
+       * guaranteed to be a multiple of 4. If it's not, we should expand
+       * the FreeType bitmap to a temporary bitmap.
        */
 
-      HSourceGlyph = EngCreateBitmap(bitSize, pitch, (glyph->bitmap.pixel_mode == ft_pixel_mode_grays) ? BMF_8BPP : BMF_1BPP, BMF_TOPDOWN, glyph->bitmap.buffer);
+      HSourceGlyph = EngCreateBitmap(bitSize, glyph->bitmap.pitch,
+                                     (glyph->bitmap.pixel_mode == ft_pixel_mode_grays) ?
+                                     BMF_8BPP : BMF_1BPP, BMF_TOPDOWN,
+                                     glyph->bitmap.buffer);
+      if ( !HSourceGlyph )
+      {
+        DPRINT1("WARNING: EngLockSurface() failed!\n");
+       IntUnLockFreeType;
+        goto fail;
+      }
       SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);
-    
+      if ( !SourceGlyphSurf )
+      {
+        EngDeleteSurface((HSURF)HSourceGlyph);
+        DPRINT1("WARNING: EngLockSurface() failed!\n");
+       IntUnLockFreeType;
+        goto fail;
+      }
+
       /*
        * Use the font data as a mask to paint onto the DCs surface using a
        * brush.
        */
 
+      if (lprc &&
+          (fuOptions & ETO_CLIPPED) &&
+          DestRect.right >= SpecifiedDestRect.right + dc->w.DCOrgX)
+      {
+         // We do the check '>=' instead of '>' to possibly save an iteration
+         // through this loop, since it's breaking after the drawing is done,
+         // and x is always incremented.
+         DestRect.right = SpecifiedDestRect.right + dc->w.DCOrgX;
+         DoBreak = TRUE;
+      }
+
       IntEngMaskBlt(
          SurfObj,
          SourceGlyphSurf,
@@ -1890,56 +1890,69 @@ NtGdiExtTextOut(
       EngUnlockSurface(SourceGlyphSurf);
       EngDeleteSurface((HSURF)HSourceGlyph);
 
+      if (DoBreak)
+      {
+         break;
+      }
+
       if (NULL == Dx)
       {
-        TextLeft += (glyph->advance.x + 32) >> 6;
+         TextLeft += glyph->advance.x;
       }
       else
       {
-        TextLeft += Dx[i];
+         TextLeft += Dx[i] << 6;
       }
       previous = glyph_index;
 
       String++;
    }
 
+   IntUnLockFreeType;
+
    EngDeleteXlate(XlateObj);
    EngDeleteXlate(XlateObj2);
-   BITMAPOBJ_UnlockBitmap(dc->w.hBitmap);
-   TEXTOBJ_UnlockText(dc->w.hFont);
+   BITMAPOBJ_UnlockBitmap(BitmapObj);
+   if(TextObj != NULL)
+     TEXTOBJ_UnlockText(TextObj);
    if (hBrushBg != NULL)
    {
-      BRUSHOBJ_UnlockBrush(hBrushBg);
+      BRUSHOBJ_UnlockBrush(BrushBg);
       NtGdiDeleteObject(hBrushBg);
    }
-   BRUSHOBJ_UnlockBrush(hBrushFg);
+   BRUSHOBJ_UnlockBrush(BrushFg);
    NtGdiDeleteObject(hBrushFg);
    if (NULL != Dx)
    {
       ExFreePool(Dx);
    }
-   DC_UnlockDc(hDC);
+   DC_UnlockDc( dc );
+
    return TRUE;
 
 fail:
-   TEXTOBJ_UnlockText(dc->w.hFont);
-   BITMAPOBJ_UnlockBitmap(dc->w.hBitmap);
+   if ( XlateObj2 != NULL )
+      EngDeleteXlate(XlateObj2);
+   if ( XlateObj != NULL )
+      EngDeleteXlate(XlateObj);
+   if(TextObj != NULL)
+     TEXTOBJ_UnlockText(TextObj);
+   BITMAPOBJ_UnlockBitmap(BitmapObj);
    if (hBrushBg != NULL)
    {
-      BRUSHOBJ_UnlockBrush(hBrushBg);
+      BRUSHOBJ_UnlockBrush(BrushBg);
       NtGdiDeleteObject(hBrushBg);
    }
    if (hBrushFg != NULL)
    {
-      BRUSHOBJ_UnlockBrush(hBrushFg);
+      BRUSHOBJ_UnlockBrush(BrushFg);
       NtGdiDeleteObject(hBrushFg);
    }
    if (NULL != Dx)
    {
       ExFreePool(Dx);
    }
-   DC_UnlockDc(hDC);
+   DC_UnlockDc(dc);
 
    return FALSE;
 }
@@ -2027,7 +2040,7 @@ NtGdiGetCharWidth32(HDC  hDC,
    }
    hFont = dc->w.hFont;
    TextObj = TEXTOBJ_LockText(hFont);
-   DC_UnlockDc(hDC);
+   DC_UnlockDc(dc);
 
    if (TextObj == NULL)
    {
@@ -2036,14 +2049,8 @@ NtGdiGetCharWidth32(HDC  hDC,
       return FALSE;
    }
 
-   if (!NT_SUCCESS(GetFontObjectsFromTextObj(TextObj, NULL, NULL, &FontGDI)))
-   {
-      ExFreePool(SafeBuffer);
-      SetLastWin32Error(ERROR_INVALID_HANDLE);
-      TEXTOBJ_UnlockText(hFont);
-      return FALSE;
-   }
-   
+   FontGDI = ObjToGDI(TextObj->Font, FONT);
+
    face = FontGDI->face;
    if (face->charmap == NULL)
    {
@@ -2072,20 +2079,20 @@ NtGdiGetCharWidth32(HDC  hDC,
 
    IntLockFreeType;
    FT_Set_Pixel_Sizes(face,
+                      TextObj->logfont.lfWidth,
                       /* FIXME should set character height if neg */
                       (TextObj->logfont.lfHeight < 0 ?
                        - TextObj->logfont.lfHeight :
-                       TextObj->logfont.lfHeight),
-                      TextObj->logfont.lfWidth);
+                       TextObj->logfont.lfHeight == 0 ? 11 : TextObj->logfont.lfHeight));
 
    for (i = FirstChar; i <= LastChar; i++)
    {
       glyph_index = FT_Get_Char_Index(face, i);
       FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
-      SafeBuffer[i - FirstChar] = face->glyph->advance.x >> 6;
+      SafeBuffer[i - FirstChar] = (face->glyph->advance.x + 32) >> 6;
    }
    IntUnLockFreeType;
-   TEXTOBJ_UnlockText(hFont);
+   TEXTOBJ_UnlockText(TextObj);
    MmCopyToCaller(Buffer, SafeBuffer, BufferSize);
    ExFreePool(SafeBuffer);
    return TRUE;
@@ -2110,15 +2117,17 @@ NtGdiGetFontLanguageInfo(HDC  hDC)
   return 0;
 }
 
-DWORD
-STDCALL
-NtGdiGetGlyphOutline(HDC  hDC,
-                           UINT  Char,
-                           UINT  Format,
-                           LPGLYPHMETRICS  gm,
-                           DWORD  Bufsize,
-                           LPVOID  Buffer,
-                           CONST LPMAT2 mat2)
+ULONG
+APIENTRY
+NtGdiGetGlyphOutline(
+    IN HDC hdc,
+    IN WCHAR wch,
+    IN UINT iFormat,
+    OUT LPGLYPHMETRICS pgm,
+    IN ULONG cjBuf,
+    OUT OPTIONAL PVOID pvBuf,
+    IN LPMAT2 pmat2,
+    IN BOOL bIgnoreRotation)
 {
   UNIMPLEMENTED;
   return 0;
@@ -2145,9 +2154,10 @@ NtGdiGetOutlineTextMetrics(HDC  hDC,
 }
 
 BOOL
-STDCALL
-NtGdiGetRasterizerCaps(LPRASTERIZER_STATUS  rs,
-                            UINT  Size)
+APIENTRY
+NtGdiGetRasterizerCaps(
+    OUT LPRASTERIZER_STATUS praststat,
+    IN ULONG cjBytes)
 {
   UNIMPLEMENTED;
   return FALSE;
@@ -2161,11 +2171,12 @@ NtGdiGetTextCharset(HDC  hDC)
   return 0;
 }
 
-UINT
-STDCALL
-NtGdiGetTextCharsetInfo(HDC  hDC,
-                             LPFONTSIGNATURE  Sig,
-                             DWORD  Flags)
+INT
+APIENTRY
+NtGdiGetTextCharsetInfo(
+    IN HDC hdc,
+    OUT OPTIONAL LPFONTSIGNATURE lpSig,
+    IN DWORD dwFlags)
 {
   UNIMPLEMENTED;
   return 0;
@@ -2173,7 +2184,7 @@ NtGdiGetTextCharsetInfo(HDC  hDC,
 
 static BOOL
 FASTCALL
-TextIntGetTextExtentPoint(HDC hDC,
+TextIntGetTextExtentPoint(PDC dc,
                           PTEXTOBJ TextObj,
                           LPCWSTR String,
                           int Count,
@@ -2186,14 +2197,11 @@ TextIntGetTextExtentPoint(HDC hDC,
   FT_Face face;
   FT_GlyphSlot glyph;
   INT error, n, glyph_index, i, previous;
-  LONG TotalWidth = 0;
+  ULONGLONG TotalWidth = 0;
   FT_CharMap charmap, found = NULL;
   BOOL use_kerning;
 
-  if (!NT_SUCCESS(GetFontObjectsFromTextObj(TextObj, NULL, NULL, &FontGDI)))
-    {
-      return FALSE;
-    }
+  FontGDI = ObjToGDI(TextObj->Font, FONT);
 
   face = FontGDI->face;
   if (NULL != Fit)
@@ -2233,11 +2241,11 @@ TextIntGetTextExtentPoint(HDC hDC,
 
   IntLockFreeType;
   error = FT_Set_Pixel_Sizes(face,
+                             TextObj->logfont.lfWidth,
                              /* FIXME should set character height if neg */
                              (TextObj->logfont.lfHeight < 0 ?
                               - TextObj->logfont.lfHeight :
-                              TextObj->logfont.lfHeight),
-                             TextObj->logfont.lfWidth);
+                              TextObj->logfont.lfHeight == 0 ? 11 : TextObj->logfont.lfHeight));
   IntUnLockFreeType;
   if (error)
     {
@@ -2266,27 +2274,27 @@ TextIntGetTextExtentPoint(HDC hDC,
           IntLockFreeType;
          FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
           IntUnLockFreeType;
-         TotalWidth += delta.x >> 6;
+         TotalWidth += delta.x;
        }
 
-      TotalWidth += glyph->advance.x >> 6;
+      TotalWidth += glyph->advance.x;
 
-      if (TotalWidth <= MaxExtent && NULL != Fit)
+      if (((TotalWidth + 32) >> 6) <= MaxExtent && NULL != Fit)
        {
          *Fit = i + 1;
        }
       if (NULL != Dx)
        {
-         Dx[i] = TotalWidth;
+         Dx[i] = (TotalWidth + 32) >> 6;
        }
 
       previous = glyph_index;
       String++;
     }
 
-  Size->cx = TotalWidth;
+  Size->cx = (TotalWidth + 32) >> 6;
   Size->cy = (TextObj->logfont.lfHeight < 0 ? - TextObj->logfont.lfHeight : TextObj->logfont.lfHeight);
-  Size->cy = EngMulDiv(Size->cy, NtGdiGetDeviceCaps(hDC, LOGPIXELSY), 72);
+  Size->cy = EngMulDiv(Size->cy, IntGdiGetDeviceCaps(dc, LOGPIXELSY), 72);
 
   return TRUE;
 }
@@ -2374,10 +2382,15 @@ NtGdiGetTextExtentExPoint(HDC hDC,
       return FALSE;
     }
   TextObj = TEXTOBJ_LockText(dc->w.hFont);
-  DC_UnlockDc(hDC);
-  Result = TextIntGetTextExtentPoint(hDC, TextObj, String, Count, MaxExtent,
+  if ( TextObj )
+  {
+    Result = TextIntGetTextExtentPoint(dc, TextObj, String, Count, MaxExtent,
                                      NULL == UnsafeFit ? NULL : &Fit, Dx, &Size);
-  TEXTOBJ_UnlockText(dc->w.hFont);
+  }
+  else
+    Result = FALSE;
+  TEXTOBJ_UnlockText(TextObj);
+  DC_UnlockDc(dc);
 
   ExFreePool(String);
   if (! Result)
@@ -2496,13 +2509,15 @@ NtGdiGetTextExtentPoint32(HDC hDC,
       return FALSE;
     }
   TextObj = TEXTOBJ_LockText(dc->w.hFont);
-  DC_UnlockDc(hDC);
-  Result = TextIntGetTextExtentPoint (
-         hDC, 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);
+  if ( TextObj != NULL )
+  {
+    Result = TextIntGetTextExtentPoint (
+      dc, TextObj, String, Count, 0, NULL, NULL, &Size);
+    TEXTOBJ_UnlockText(TextObj);
+  }
+  else
+    Result = FALSE;
+  DC_UnlockDc(dc);
 
   ExFreePool(String);
   if (! Result)
@@ -2524,6 +2539,7 @@ INT STDCALL
 NtGdiGetTextFace(HDC hDC, INT Count, LPWSTR FaceName)
 {
    PDC Dc;
+   HFONT hFont;
    PTEXTOBJ TextObj;
    NTSTATUS Status;
 
@@ -2533,11 +2549,14 @@ NtGdiGetTextFace(HDC hDC, INT Count, LPWSTR FaceName)
       SetLastWin32Error(ERROR_INVALID_HANDLE);
       return FALSE;
    }
-   TextObj = TEXTOBJ_LockText(Dc->w.hFont);
-   DC_UnlockDc(hDC);
+   hFont = Dc->w.hFont;
+   DC_UnlockDc(Dc);
 
+   TextObj = TEXTOBJ_LockText(hFont);
+   ASSERT(TextObj != NULL);
    Count = min(Count, wcslen(TextObj->logfont.lfFaceName));
    Status = MmCopyToCaller(FaceName, TextObj->logfont.lfFaceName, Count * sizeof(WCHAR));
+   TEXTOBJ_UnlockText(TextObj);
    if (!NT_SUCCESS(Status))
    {
       SetLastNtError(Status);
@@ -2550,7 +2569,7 @@ NtGdiGetTextFace(HDC hDC, INT Count, LPWSTR FaceName)
 BOOL
 STDCALL
 NtGdiGetTextMetrics(HDC hDC,
-                   LPTEXTMETRICW tm)
+                    LPTEXTMETRICW tm)
 {
   PDC dc;
   PTEXTOBJ TextObj;
@@ -2559,6 +2578,7 @@ NtGdiGetTextMetrics(HDC hDC,
   TEXTMETRICW SafeTm;
   FT_Face Face;
   TT_OS2 *pOS2;
+  TT_HoriHeader *pHori;
   ULONG Error;
 
   if (NULL == tm)
@@ -2566,7 +2586,7 @@ NtGdiGetTextMetrics(HDC hDC,
     SetLastWin32Error(STATUS_INVALID_PARAMETER);
     return FALSE;
   }
-  
+
   if(!(dc = DC_LockDc(hDC)))
   {
     SetLastWin32Error(ERROR_INVALID_HANDLE);
@@ -2575,65 +2595,65 @@ NtGdiGetTextMetrics(HDC hDC,
 
   TextObj = TEXTOBJ_LockText(dc->w.hFont);
   if (NULL != TextObj)
-  {
-    Status = GetFontObjectsFromTextObj(TextObj, NULL, NULL, &FontGDI);
-    if (NT_SUCCESS(Status))
     {
+      FontGDI = ObjToGDI(TextObj->Font, FONT);
+
       Face = FontGDI->face;
       IntLockFreeType;
       Error = FT_Set_Pixel_Sizes(Face,
+                                TextObj->logfont.lfWidth,
                                 /* FIXME should set character height if neg */
-                                (TextObj->logfont.lfHeight < 0 ?
-                                 - TextObj->logfont.lfHeight :
-                                 TextObj->logfont.lfHeight),
-                                TextObj->logfont.lfWidth);
+                                 (TextObj->logfont.lfHeight < 0 ?
+                                  - TextObj->logfont.lfHeight :
+                                  TextObj->logfont.lfHeight == 0 ? 11 : TextObj->logfont.lfHeight));
       IntUnLockFreeType;
       if (0 != Error)
        {
-       DPRINT1("Error in setting pixel sizes: %u\n", Error);
-       Status = STATUS_UNSUCCESSFUL;
+          DPRINT1("Error in setting pixel sizes: %u\n", Error);
+          Status = STATUS_UNSUCCESSFUL;
        }
       else
        {
-       memcpy(&SafeTm, &FontGDI->TextMetric, sizeof(TEXTMETRICW));
-        IntLockFreeType;
-        pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
-        IntUnLockFreeType;
-        if (NULL == pOS2)
-          {
-            DPRINT1("Can't find OS/2 table - not TT font?\n");
-            Status = STATUS_UNSUCCESSFUL;
-          }
-        else
-          {
-            SafeTm.tmAveCharWidth = (pOS2->xAvgCharWidth + 32) >> 6;
-          }
-       SafeTm.tmAscent = (Face->size->metrics.ascender + 32) >> 6; // units above baseline
-       SafeTm.tmDescent = (32 - Face->size->metrics.descender) >> 6; // units below baseline
-       SafeTm.tmHeight = SafeTm.tmAscent + SafeTm.tmDescent;
-    SafeTm.tmMaxCharWidth = (Face->size->metrics.max_advance + 32) >> 6;
-    if (FT_IS_SFNT(FontGDI->face))
-    {
-      SafeTm.tmPitchAndFamily |= TMPF_TRUETYPE;
-    }
-       Status = MmCopyToCaller(tm, &SafeTm, sizeof(TEXTMETRICW));
+          memcpy(&SafeTm, &FontGDI->TextMetric, sizeof(TEXTMETRICW));
+
+          Status = STATUS_SUCCESS;
+          IntLockFreeType;
+          pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2);
+          if (NULL == pOS2)
+            {
+              DPRINT1("Can't find OS/2 table - not TT font?\n");
+              Status = STATUS_INTERNAL_ERROR;
+            }
+
+          pHori = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_hhea);
+          if (NULL == pHori)
+            {
+              DPRINT1("Can't find HHEA table - not TT font?\n");
+              Status = STATUS_INTERNAL_ERROR;
+            }
+
+          IntUnLockFreeType;
+
+          if (NT_SUCCESS(Status))
+            {
+              FillTM(&SafeTm, FontGDI->face, pOS2, pHori);
+              Status = MmCopyToCaller(tm, &SafeTm, sizeof(TEXTMETRICW));
+            }
        }
+      TEXTOBJ_UnlockText(TextObj);
     }
-    TEXTOBJ_UnlockText(dc->w.hFont);
-  }
   else
-  {
-    ASSERT(FALSE);
-    Status = STATUS_INVALID_HANDLE;
-  }
-  DC_UnlockDc(hDC);
-  
+    {
+      Status = STATUS_INVALID_HANDLE;
+    }
+  DC_UnlockDc(dc);
+
   if(!NT_SUCCESS(Status))
-  {
-    SetLastNtError(Status);
-    return FALSE;
-  }
-  
+    {
+      SetLastNtError(Status);
+      return FALSE;
+    }
+
   return TRUE;
 }
 
@@ -2651,7 +2671,7 @@ BOOL
 STDCALL
 NtGdiRemoveFontResource(LPCWSTR  FileName)
 {
-  UNIMPLEMENTED;
+  DPRINT1("NtGdiRemoveFontResource is UNIMPLEMENTED\n");
   return FALSE;
 }
 
@@ -2680,7 +2700,7 @@ NtGdiSetTextAlign(HDC  hDC,
     }
   prevAlign = dc->w.textAlign;
   dc->w.textAlign = Mode;
-  DC_UnlockDc( hDC );
+  DC_UnlockDc( dc );
   return  prevAlign;
 }
 
@@ -2702,7 +2722,7 @@ NtGdiSetTextColor(HDC hDC,
   oldColor = dc->w.textColor;
   dc->w.textColor = color;
   hBrush = dc->w.hBrush;
-  DC_UnlockDc( hDC );
+  DC_UnlockDc( dc );
   NtGdiSelectObject(hDC, hBrush);
   return  oldColor;
 }
@@ -2741,7 +2761,6 @@ NtGdiGetFontData(
    PTEXTOBJ TextObj;
    PFONTGDI FontGdi;
    DWORD Result = GDI_ERROR;
-   NTSTATUS Status;
 
    Dc = DC_LockDc(hDC);
    if (Dc == NULL)
@@ -2751,38 +2770,36 @@ NtGdiGetFontData(
    }
    hFont = Dc->w.hFont;
    TextObj = TEXTOBJ_LockText(hFont);
-   DC_UnlockDc(hDC);
+   DC_UnlockDc(Dc);
 
    if (TextObj == NULL)
    {
       SetLastWin32Error(ERROR_INVALID_HANDLE);
       return GDI_ERROR;
    }
-   
-   Status = GetFontObjectsFromTextObj(TextObj, NULL, NULL, &FontGdi);
-   if (NT_SUCCESS(Status))
-   {
-      IntLockFreeType;
 
-      if (FT_IS_SFNT(FontGdi->face))
-      {
-         if (Table)
-            Table = Table >> 24 | Table << 24 | (Table >> 8 & 0xFF00) |
-                    (Table << 8 & 0xFF0000);
+   FontGdi = ObjToGDI(TextObj->Font, FONT);
 
-         if (Buffer == NULL)
-            Size = 0;
+   IntLockFreeType;
 
-         if (!FT_Load_Sfnt_Table(FontGdi->face, Table, Offset, Buffer, &Size))
-            Result = Size;
-      }
+   if (FT_IS_SFNT(FontGdi->face))
+   {
+       if (Table)
+          Table = Table >> 24 | Table << 24 | (Table >> 8 & 0xFF00) |
+                  (Table << 8 & 0xFF0000);
 
-      IntUnLockFreeType;
+       if (Buffer == NULL)
+          Size = 0;
+
+       if (!FT_Load_Sfnt_Table(FontGdi->face, Table, Offset, Buffer, &Size))
+          Result = Size;
    }
 
-   TEXTOBJ_UnlockText(hFont);
+   IntUnLockFreeType;
+
+   TEXTOBJ_UnlockText(TextObj);
 
-   return Result; 
+   return Result;
 }
 
 static UINT FASTCALL
@@ -2795,7 +2812,7 @@ GetFontScore(LOGFONTW *LogFont, PUNICODE_STRING FaceName, PFONTGDI FontGDI)
   LONG WeightDiff;
   NTSTATUS Status;
   UINT Score = 1;
-  
+
   RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name);
   Status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
   if (NT_SUCCESS(Status))
@@ -2840,35 +2857,34 @@ GetFontScore(LOGFONTW *LogFont, PUNICODE_STRING FaceName, PFONTGDI FontGDI)
   return Score;
 }
 
-static VOID FASTCALL
-FindBestFontFromList(HFONT *Font, UINT *MatchScore, LOGFONTW *LogFont,
+static __inline VOID
+FindBestFontFromList(FONTOBJ **FontObj, UINT *MatchScore, LOGFONTW *LogFont,
                      PUNICODE_STRING FaceName, PLIST_ENTRY Head)
 {
   PLIST_ENTRY Entry;
   PFONT_ENTRY CurrentEntry;
-  PFONTGDI FontGDI;
+  FONTGDI *FontGDI;
   UINT Score;
 
   Entry = Head->Flink;
   while (Entry != Head)
     {
       CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
-      if (NULL == (FontGDI = AccessInternalObject((ULONG) CurrentEntry->hFont)))
-        {
-          Entry = Entry->Flink;
-          continue;
-        }
+
+      FontGDI = CurrentEntry->Font;
+      ASSERT(FontGDI);
+
       Score = GetFontScore(LogFont, FaceName, FontGDI);
-      if (*MatchScore < Score)
+      if (*MatchScore == 0 || *MatchScore < Score)
         {
-          *Font = CurrentEntry->hFont;
+          *FontObj = GDIToObj(FontGDI, FONT);
           *MatchScore = Score;
         }
       Entry = Entry->Flink;
     }
 }
 
-static BOOLEAN FASTCALL
+static __inline BOOLEAN
 SubstituteFontFamilyKey(PUNICODE_STRING FaceName,
                         LPCWSTR Key)
 {
@@ -2904,7 +2920,7 @@ SubstituteFontFamilyKey(PUNICODE_STRING FaceName,
   return NT_SUCCESS(Status);
 }
 
-static void FASTCALL
+static __inline void
 SubstituteFontFamily(PUNICODE_STRING FaceName, UINT Level)
 {
   if (10 < Level) /* Enough is enough */
@@ -2934,40 +2950,52 @@ TextIntRealizeFont(HFONT FontHandle)
       return STATUS_INVALID_HANDLE;
     }
 
+  if (TextObj->Initialized)
+    {
+      TEXTOBJ_UnlockText(TextObj);
+      return STATUS_SUCCESS;
+    }
+
   if (! RtlCreateUnicodeString(&FaceName, TextObj->logfont.lfFaceName))
     {
-      TEXTOBJ_UnlockText(FontHandle);
+      TEXTOBJ_UnlockText(TextObj);
       return STATUS_NO_MEMORY;
     }
   SubstituteFontFamily(&FaceName, 0);
   MatchScore = 0;
-  TextObj->GDIFontHandle = NULL;
-    
+  TextObj->Font = NULL;
+
   /* First search private fonts */
   Win32Process = PsGetWin32Process();
   IntLockProcessPrivateFonts(Win32Process);
-  FindBestFontFromList(&TextObj->GDIFontHandle, &MatchScore,
+  FindBestFontFromList(&TextObj->Font, &MatchScore,
                        &TextObj->logfont, &FaceName,
                        &Win32Process->PrivateFontListHead);
   IntUnLockProcessPrivateFonts(Win32Process);
-    
+
   /* Search system fonts */
   IntLockGlobalFonts;
-  FindBestFontFromList(&TextObj->GDIFontHandle, &MatchScore,
+  FindBestFontFromList(&TextObj->Font, &MatchScore,
                        &TextObj->logfont, &FaceName,
                        &FontListHead);
   IntUnLockGlobalFonts;
 
-  if (NULL == TextObj->GDIFontHandle)
+  if (NULL == TextObj->Font)
     {
       DPRINT1("Requested font %S not found, no fonts loaded at all\n",
               TextObj->logfont.lfFaceName);
       Status = STATUS_NOT_FOUND;
     }
+  else
+    {
+      TextObj->Initialized = TRUE;
+      Status = STATUS_SUCCESS;
+    }
 
   RtlFreeUnicodeString(&FaceName);
-  TEXTOBJ_UnlockText(FontHandle);
-  ASSERT(! NT_SUCCESS(Status) && NULL != TextObj->GDIFontHandle);
+  TEXTOBJ_UnlockText(TextObj);
+
+  ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0);
 
   return Status;
 }