[WIN32K]
[reactos.git] / reactos / win32ss / gdi / ntgdi / freetype.c
index 14a0afa..e47bdaf 100644 (file)
 
 #include <win32k.h>
 
+#include FT_GLYPH_H
+#include FT_TYPE1_TABLES_H
+#include <tttables.h>
+#include <fttrigon.h>
+#include <ftbitmap.h>
+#include <ftoutln.h>
+#include <ftwinfnt.h>
+
+#include <gdi/eng/floatobj.h>
+
 #define NDEBUG
 #include <debug.h>
 
@@ -59,6 +69,7 @@ typedef struct _FONT_CACHE_ENTRY
     FT_Face Face;
     FT_BitmapGlyph BitmapGlyph;
     int Height;
+    MATRIX mxWorldToDevice;
 } FONT_CACHE_ENTRY, *PFONT_CACHE_ENTRY;
 static LIST_ENTRY FontCacheListHead;
 static UINT FontCacheNumEntries;
@@ -158,6 +169,35 @@ InitFontSupport(VOID)
     return TRUE;
 }
 
+VOID
+FtSetCoordinateTransform(
+    FT_Face face,
+    PMATRIX pmx)
+{
+    FT_Matrix ftmatrix;
+    FLOATOBJ efTemp;
+
+    /* Create a freetype matrix, by converting to 16.16 fixpoint format */
+    efTemp = pmx->efM11;
+    FLOATOBJ_MulLong(&efTemp, 0x00010000);
+    ftmatrix.xx = FLOATOBJ_GetLong(&efTemp);
+
+    efTemp = pmx->efM12;
+    FLOATOBJ_MulLong(&efTemp, 0x00010000);
+    ftmatrix.xy = FLOATOBJ_GetLong(&efTemp);
+
+    efTemp = pmx->efM21;
+    FLOATOBJ_MulLong(&efTemp, 0x00010000);
+    ftmatrix.yx = FLOATOBJ_GetLong(&efTemp);
+
+    efTemp = pmx->efM22;
+    FLOATOBJ_MulLong(&efTemp, 0x00010000);
+    ftmatrix.yy = FLOATOBJ_GetLong(&efTemp);
+
+    /* Set the transformation matrix */
+    FT_Set_Transform(face, &ftmatrix, 0);
+}
+
 /*
  * IntLoadSystemFonts
  *
@@ -277,7 +317,7 @@ IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
     FT_Face Face;
     ANSI_STRING AnsiFaceName;
     PFONT_ENTRY Entry;
-    PSECTION_OBJECT SectionObject;
+    PVOID SectionObject;
     ULONG ViewSize = 0;
     LARGE_INTEGER SectionSize;
     UNICODE_STRING FontRegPath = RTL_CONSTANT_STRING(L"\\REGISTRY\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts");
@@ -300,7 +340,7 @@ IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
     }
 
     SectionSize.QuadPart = 0LL;
-    Status = MmCreateSection((PVOID)&SectionObject, SECTION_ALL_ACCESS,
+    Status = MmCreateSection(&SectionObject, SECTION_ALL_ACCESS,
                              NULL, &SectionSize, PAGE_READONLY,
                              SEC_COMMIT, FileHandle, NULL);
     if (!NT_SUCCESS(Status))
@@ -316,7 +356,8 @@ IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
     if (!NT_SUCCESS(Status))
     {
         DPRINT("Could not map file: %wZ\n", FileName);
-        return Status;
+        ObDereferenceObject(SectionObject);
+        return 0;
     }
 
     IntLockFreeType;
@@ -327,14 +368,14 @@ IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
                 0,
                 &Face);
     IntUnLockFreeType;
+    ObDereferenceObject(SectionObject);
 
     if (Error)
     {
         if (Error == FT_Err_Unknown_File_Format)
             DPRINT("Unknown font file format\n");
         else
-            DPRINT("Error reading font file (error code: %u)\n", Error);
-        ObDereferenceObject(SectionObject);
+            DPRINT("Error reading font file (error code: %d)\n", Error);
         return 0;
     }
 
@@ -342,7 +383,6 @@ IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
     if (!Entry)
     {
         FT_Done_Face(Face);
-        ObDereferenceObject(SectionObject);
         EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
         return 0;
     }
@@ -351,7 +391,6 @@ IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
     if (FontGDI == NULL)
     {
         FT_Done_Face(Face);
-        ObDereferenceObject(SectionObject);
         ExFreePoolWithTag(Entry, TAG_FONT);
         EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
         return 0;
@@ -362,7 +401,6 @@ IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
     {
         EngFreeMem(FontGDI);
         FT_Done_Face(Face);
-        ObDereferenceObject(SectionObject);
         ExFreePoolWithTag(Entry, TAG_FONT);
         EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
         return 0;
@@ -372,7 +410,7 @@ IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
     FontGDI->face = Face;
 
     DPRINT("Font loaded: %s (%s)\n", Face->family_name, Face->style_name);
-    DPRINT("Num glyphs: %u\n", Face->num_glyphs);
+    DPRINT("Num glyphs: %d\n", Face->num_glyphs);
 
     /* Add this font resource to the font table */
 
@@ -497,19 +535,19 @@ IntTranslateCharsetInfo(PDWORD Src, /* [in]
     switch (Flags)
     {
     case TCI_SRCFONTSIG:
-        while (0 == (*Src >> Index & 0x0001) && Index < MAXTCIINDEX)
+        while (Index < MAXTCIINDEX && 0 == (*Src >> Index & 0x0001))
         {
             Index++;
         }
         break;
     case TCI_SRCCODEPAGE:
-        while ( *Src != FontTci[Index].ciACP && Index < MAXTCIINDEX)
+        while (Index < MAXTCIINDEX && *Src != FontTci[Index].ciACP)
         {
             Index++;
         }
         break;
     case TCI_SRCCHARSET:
-        while ( *Src != FontTci[Index].ciCharset && Index < MAXTCIINDEX)
+        while (Index < MAXTCIINDEX && *Src != FontTci[Index].ciCharset)
         {
             Index++;
         }
@@ -1099,7 +1137,7 @@ FontFamilyFillInfo(PFONTFAMILYINFO Info, PCWSTR FaceName, PFONTGDI FontGDI)
                         wcscpy(Info->EnumLogFontEx.elfScript, ElfScripts[i]);
                     else
                     {
-                        DPRINT1("Unknown elfscript for bit %d\n", i);
+                        DPRINT1("Unknown elfscript for bit %u\n", i);
                     }
                 }
             }
@@ -1264,7 +1302,7 @@ GetFontFamilyInfoForSubstitutes(LPLOGFONTW LogFont,
     FONT_FAMILY_INFO_CALLBACK_CONTEXT Context;
     NTSTATUS Status;
 
-    /* Enumerate font families found in HKLM\Software\Microsoft\Windows NT\CurrentVersion\SysFontSubstitutes
+    /* Enumerate font families found in HKLM\Software\Microsoft\Windows NT\CurrentVersion\FontSubstitutes
        The real work is done in the registry callback function */
     Context.LogFont = LogFont;
     Context.Info = Info;
@@ -1283,7 +1321,7 @@ GetFontFamilyInfoForSubstitutes(LPLOGFONTW LogFont,
     QueryTable[1].Name = NULL;
 
     Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
-                                    L"SysFontSubstitutes",
+                                    L"FontSubstitutes",
                                     QueryTable,
                                     &Context,
                                     NULL);
@@ -1310,12 +1348,24 @@ ftGdiGetRasterizerCaps(LPRASTERIZER_STATUS lprs)
     return FALSE;
 }
 
+static
+BOOL
+SameScaleMatrix(
+    PMATRIX pmx1,
+    PMATRIX pmx2)
+{
+    return (FLOATOBJ_Equal(&pmx1->efM11, &pmx2->efM11) &&
+            FLOATOBJ_Equal(&pmx1->efM12, &pmx2->efM12) &&
+            FLOATOBJ_Equal(&pmx1->efM21, &pmx2->efM21) &&
+            FLOATOBJ_Equal(&pmx1->efM22, &pmx2->efM22));
+}
 
 FT_BitmapGlyph APIENTRY
 ftGdiGlyphCacheGet(
     FT_Face Face,
     INT GlyphIndex,
-    INT Height)
+    INT Height,
+    PMATRIX pmx)
 {
     PLIST_ENTRY CurrentEntry;
     PFONT_CACHE_ENTRY FontEntry;
@@ -1324,9 +1374,10 @@ ftGdiGlyphCacheGet(
     while (CurrentEntry != &FontCacheListHead)
     {
         FontEntry = (PFONT_CACHE_ENTRY)CurrentEntry;
-        if (FontEntry->Face == Face &&
-                FontEntry->GlyphIndex == GlyphIndex &&
-                FontEntry->Height == Height)
+        if ((FontEntry->Face == Face) &&
+            (FontEntry->GlyphIndex == GlyphIndex) &&
+            (FontEntry->Height == Height) &&
+            (SameScaleMatrix(&FontEntry->mxWorldToDevice, pmx)))
             break;
         CurrentEntry = CurrentEntry->Flink;
     }
@@ -1346,6 +1397,7 @@ ftGdiGlyphCacheSet(
     FT_Face Face,
     INT GlyphIndex,
     INT Height,
+    PMATRIX pmx,
     FT_GlyphSlot GlyphSlot,
     FT_Render_Mode RenderMode)
 {
@@ -1395,6 +1447,7 @@ ftGdiGlyphCacheSet(
     NewEntry->Face = Face;
     NewEntry->BitmapGlyph = BitmapGlyph;
     NewEntry->Height = Height;
+    NewEntry->mxWorldToDevice = *pmx;
 
     InsertHeadList(&FontCacheListHead, &NewEntry->ListEntry);
     if (FontCacheNumEntries++ > MAX_FONT_CACHE)
@@ -1402,7 +1455,7 @@ ftGdiGlyphCacheSet(
         NewEntry = (PFONT_CACHE_ENTRY)FontCacheListHead.Blink;
         FT_Done_Glyph((FT_Glyph)NewEntry->BitmapGlyph);
         RemoveTailList(&FontCacheListHead);
-        ExFreePool(NewEntry);
+        ExFreePoolWithTag(NewEntry, TAG_FONT);
         FontCacheNumEntries--;
     }
 
@@ -1444,6 +1497,203 @@ static __inline FT_Fixed FT_FixedFromFIXED(FIXED f)
     return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
 }
 
+static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
+{
+    TTPOLYGONHEADER *pph;
+    TTPOLYCURVE *ppc;
+    unsigned int needed = 0, point = 0, contour, first_pt;
+    unsigned int pph_start, cpfx;
+    DWORD type;
+
+    for (contour = 0; contour < outline->n_contours; contour++)
+    {
+        /* Ignore contours containing one point */
+        if (point == outline->contours[contour])
+        {
+            point++;
+            continue;
+        }
+
+        pph_start = needed;
+        pph = (TTPOLYGONHEADER *)(buf + needed);
+        first_pt = point;
+        if (buf)
+        {
+            pph->dwType = TT_POLYGON_TYPE;
+            FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
+        }
+        needed += sizeof(*pph);
+        point++;
+        while (point <= outline->contours[contour])
+        {
+            ppc = (TTPOLYCURVE *)(buf + needed);
+            type = outline->tags[point] & FT_Curve_Tag_On ?
+                TT_PRIM_LINE : TT_PRIM_QSPLINE;
+            cpfx = 0;
+            do
+            {
+                if (buf)
+                    FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
+                cpfx++;
+                point++;
+            } while (point <= outline->contours[contour] &&
+                    (outline->tags[point] & FT_Curve_Tag_On) ==
+                    (outline->tags[point-1] & FT_Curve_Tag_On));
+            /* At the end of a contour Windows adds the start point, but
+               only for Beziers */
+            if (point > outline->contours[contour] &&
+               !(outline->tags[point-1] & FT_Curve_Tag_On))
+            {
+                if (buf)
+                    FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
+                cpfx++;
+            }
+            else if (point <= outline->contours[contour] &&
+                      outline->tags[point] & FT_Curve_Tag_On)
+            {
+                /* add closing pt for bezier */
+                if (buf)
+                    FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
+                cpfx++;
+                point++;
+            }
+            if (buf)
+            {
+                ppc->wType = type;
+                ppc->cpfx = cpfx;
+            }
+            needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
+        }
+        if (buf)
+            pph->cb = needed - pph_start;
+    }
+    return needed;
+}
+
+static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
+{
+    /* Convert the quadratic Beziers to cubic Beziers.
+       The parametric eqn for a cubic Bezier is, from PLRM:
+       r(t) = at^3 + bt^2 + ct + r0
+       with the control points:
+       r1 = r0 + c/3
+       r2 = r1 + (c + b)/3
+       r3 = r0 + c + b + a
+
+       A quadratic Bezier has the form:
+       p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
+
+       So equating powers of t leads to:
+       r1 = 2/3 p1 + 1/3 p0
+       r2 = 2/3 p1 + 1/3 p2
+       and of course r0 = p0, r3 = p2
+    */
+    int contour, point = 0, first_pt;
+    TTPOLYGONHEADER *pph;
+    TTPOLYCURVE *ppc;
+    DWORD pph_start, cpfx, type;
+    FT_Vector cubic_control[4];
+    unsigned int needed = 0;
+
+    for (contour = 0; contour < outline->n_contours; contour++)
+    {
+        pph_start = needed;
+        pph = (TTPOLYGONHEADER *)(buf + needed);
+        first_pt = point;
+        if (buf)
+        {
+            pph->dwType = TT_POLYGON_TYPE;
+            FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
+        }
+        needed += sizeof(*pph);
+        point++;
+        while (point <= outline->contours[contour])
+        {
+            ppc = (TTPOLYCURVE *)(buf + needed);
+            type = outline->tags[point] & FT_Curve_Tag_On ?
+                TT_PRIM_LINE : TT_PRIM_CSPLINE;
+            cpfx = 0;
+            do
+            {
+                if (type == TT_PRIM_LINE)
+                {
+                    if (buf)
+                        FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
+                    cpfx++;
+                    point++;
+                }
+                else
+                {
+                    /* Unlike QSPLINEs, CSPLINEs always have their endpoint
+                       so cpfx = 3n */
+
+                    /* FIXME: Possible optimization in endpoint calculation
+                       if there are two consecutive curves */
+                    cubic_control[0] = outline->points[point-1];
+                    if (!(outline->tags[point-1] & FT_Curve_Tag_On))
+                    {
+                        cubic_control[0].x += outline->points[point].x + 1;
+                        cubic_control[0].y += outline->points[point].y + 1;
+                        cubic_control[0].x >>= 1;
+                        cubic_control[0].y >>= 1;
+                    }
+                    if (point+1 > outline->contours[contour])
+                        cubic_control[3] = outline->points[first_pt];
+                    else
+                    {
+                        cubic_control[3] = outline->points[point+1];
+                        if (!(outline->tags[point+1] & FT_Curve_Tag_On))
+                        {
+                            cubic_control[3].x += outline->points[point].x + 1;
+                            cubic_control[3].y += outline->points[point].y + 1;
+                            cubic_control[3].x >>= 1;
+                            cubic_control[3].y >>= 1;
+                        }
+                    }
+                    /* r1 = 1/3 p0 + 2/3 p1
+                       r2 = 1/3 p2 + 2/3 p1 */
+                    cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
+                    cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
+                    cubic_control[2] = cubic_control[1];
+                    cubic_control[1].x += (cubic_control[0].x + 1) / 3;
+                    cubic_control[1].y += (cubic_control[0].y + 1) / 3;
+                    cubic_control[2].x += (cubic_control[3].x + 1) / 3;
+                    cubic_control[2].y += (cubic_control[3].y + 1) / 3;
+                    if (buf)
+                    {
+                        FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
+                        FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
+                        FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
+                    }
+                    cpfx += 3;
+                    point++;
+                }
+            } while (point <= outline->contours[contour] &&
+                    (outline->tags[point] & FT_Curve_Tag_On) ==
+                    (outline->tags[point-1] & FT_Curve_Tag_On));
+            /* At the end of a contour Windows adds the start point,
+               but only for Beziers and we've already done that.
+            */
+            if (point <= outline->contours[contour] &&
+               outline->tags[point] & FT_Curve_Tag_On)
+            {
+                /* This is the closing pt of a bezier, but we've already
+                   added it, so just inc point and carry on */
+                point++;
+            }
+            if (buf)
+            {
+                ppc->wType = type;
+                ppc->cpfx = cpfx;
+            }
+            needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
+        }
+        if (buf)
+            pph->cb = needed - pph_start;
+    }
+    return needed;
+}
+
 /*
  * Based on WineEngGetGlyphOutline
  *
@@ -1486,7 +1736,7 @@ ftGdiGetGlyphOutline(
     FT_CharMap found = 0, charmap;
     XFORM xForm;
 
-    DPRINT("%d, %08x, %p, %08lx, %p, %p\n", wch, iFormat, pgm,
+    DPRINT("%u, %08x, %p, %08lx, %p, %p\n", wch, iFormat, pgm,
            cjBuf, pvBuf, pmat2);
 
     pdcattr = dc->pdcattr;
@@ -1547,11 +1797,12 @@ ftGdiGetGlyphOutline(
         }
     }
 
-//  FT_Set_Pixel_Sizes(ft_face,
-//                     TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
+    FT_Set_Pixel_Sizes(ft_face,
+                       abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth),
     /* FIXME: Should set character height if neg */
-//                     (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ?
-//                      dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)));
+                       (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ?
+                        dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)));
+    FtSetCoordinateTransform(ft_face, DC_pmxWorldToDevice(dc));
 
     TEXTOBJ_UnlockText(TextObj);
 
@@ -1600,15 +1851,32 @@ ftGdiGetGlyphOutline(
     IntLockFreeType;
 
     /* Scaling transform */
-    if (aveWidth)
-    {
-        FT_Matrix scaleMat;
-        DPRINT("Scaling Trans!\n");
-        scaleMat.xx = FT_FixedFromFloat(widthRatio);
-        scaleMat.xy = 0;
-        scaleMat.yx = 0;
-        scaleMat.yy = (1 << 16);
-        FT_Matrix_Multiply(&scaleMat, &transMat);
+    /*if (aveWidth)*/
+    {
+
+        FT_Matrix ftmatrix;
+        FLOATOBJ efTemp;
+
+        PMATRIX pmx = DC_pmxWorldToDevice(dc);
+
+        /* Create a freetype matrix, by converting to 16.16 fixpoint format */
+        efTemp = pmx->efM11;
+        FLOATOBJ_MulLong(&efTemp, 0x00010000);
+        ftmatrix.xx = FLOATOBJ_GetLong(&efTemp);
+
+        efTemp = pmx->efM12;
+        FLOATOBJ_MulLong(&efTemp, 0x00010000);
+        ftmatrix.xy = FLOATOBJ_GetLong(&efTemp);
+
+        efTemp = pmx->efM21;
+        FLOATOBJ_MulLong(&efTemp, 0x00010000);
+        ftmatrix.yx = FLOATOBJ_GetLong(&efTemp);
+
+        efTemp = pmx->efM22;
+        FLOATOBJ_MulLong(&efTemp, 0x00010000);
+        ftmatrix.yy = FLOATOBJ_GetLong(&efTemp);
+
+        FT_Matrix_Multiply(&ftmatrix, &transMat);
         needsTransform = TRUE;
     }
 
@@ -1710,7 +1978,7 @@ ftGdiGetGlyphOutline(
     gm.gmptGlyphOrigin.x = left >> 6;
     gm.gmptGlyphOrigin.y = top >> 6;
 
-    DPRINT("CX %d CY %d BBX %d BBY %d GOX %d GOY %d\n",
+    DPRINT("CX %d CY %d BBX %u BBY %u GOX %d GOY %d\n",
            gm.gmCellIncX, gm.gmCellIncY,
            gm.gmBlackBoxX, gm.gmBlackBoxY,
            gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
@@ -1865,101 +2133,32 @@ ftGdiGetGlyphOutline(
 
     case GGO_NATIVE:
     {
-        int contour, point = 0, first_pt;
         FT_Outline *outline = &ft_face->glyph->outline;
-        TTPOLYGONHEADER *pph;
-        TTPOLYCURVE *ppc;
-        DWORD pph_start, cpfx, type;
 
         if (cjBuf == 0) pvBuf = NULL; /* This is okay, need cjBuf to allocate. */
 
         IntLockFreeType;
         if (needsTransform && pvBuf) FT_Outline_Transform(outline, &transMat);
 
-        for (contour = 0; contour < outline->n_contours; contour++)
+        needed = get_native_glyph_outline(outline, cjBuf, NULL);
+
+        if (!pvBuf || !cjBuf)
         {
-            pph_start = needed;
-            pph = (TTPOLYGONHEADER *)((char *)pvBuf + needed);
-            first_pt = point;
-            if (pvBuf)
-            {
-                pph->dwType = TT_POLYGON_TYPE;
-                FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
-            }
-            needed += sizeof(*pph);
-            point++;
-            while (point <= outline->contours[contour])
-            {
-                ppc = (TTPOLYCURVE *)((char *)pvBuf + needed);
-                type = (outline->tags[point] & FT_Curve_Tag_On) ?
-                       TT_PRIM_LINE : TT_PRIM_QSPLINE;
-                cpfx = 0;
-                do
-                {
-                    if (pvBuf)
-                        FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
-                    cpfx++;
-                    point++;
-                }
-                while (point <= outline->contours[contour] &&
-                        (outline->tags[point] & FT_Curve_Tag_On) ==
-                        (outline->tags[point-1] & FT_Curve_Tag_On));
-
-                /* At the end of a contour Windows adds the start point, but
-                   only for Beziers */
-                if (point > outline->contours[contour] &&
-                        !(outline->tags[point-1] & FT_Curve_Tag_On))
-                {
-                    if (pvBuf)
-                        FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
-                    cpfx++;
-                }
-                else if (point <= outline->contours[contour] &&
-                         outline->tags[point] & FT_Curve_Tag_On)
-                {
-                    /* Add closing pt for bezier */
-                    if (pvBuf)
-                        FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
-                    cpfx++;
-                    point++;
-                }
-                if (pvBuf)
-                {
-                    ppc->wType = type;
-                    ppc->cpfx = cpfx;
-                }
-                needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
-            }
-            if (pvBuf) pph->cb = needed - pph_start;
+            IntUnLockFreeType;
+            break;
         }
+        if (needed > cjBuf)
+        {
+            IntUnLockFreeType;
+            return GDI_ERROR;
+        }
+        get_native_glyph_outline(outline, cjBuf, pvBuf);
         IntUnLockFreeType;
         break;
     }
     case GGO_BEZIER:
     {
-        /* Convert the quadratic Beziers to cubic Beziers.
-           The parametric eqn for a cubic Bezier is, from PLRM:
-           r(t) = at^3 + bt^2 + ct + r0
-           with the control points:
-           r1 = r0 + c/3
-           r2 = r1 + (c + b)/3
-           r3 = r0 + c + b + a
-
-           A quadratic Beizer has the form:
-           p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
-
-           So equating powers of t leads to:
-           r1 = 2/3 p1 + 1/3 p0
-           r2 = 2/3 p1 + 1/3 p2
-           and of course r0 = p0, r3 = p2
-         */
-
-        int contour, point = 0, first_pt;
         FT_Outline *outline = &ft_face->glyph->outline;
-        TTPOLYGONHEADER *pph;
-        TTPOLYCURVE *ppc;
-        DWORD pph_start, cpfx, type;
-        FT_Vector cubic_control[4];
         if (cjBuf == 0) pvBuf = NULL;
 
         if (needsTransform && pvBuf)
@@ -1968,111 +2167,23 @@ ftGdiGetGlyphOutline(
             FT_Outline_Transform(outline, &transMat);
             IntUnLockFreeType;
         }
+        needed = get_bezier_glyph_outline(outline, cjBuf, NULL);
 
-        for (contour = 0; contour < outline->n_contours; contour++)
-        {
-            pph_start = needed;
-            pph = (TTPOLYGONHEADER *)((char *)pvBuf + needed);
-            first_pt = point;
-            if (pvBuf)
-            {
-                pph->dwType = TT_POLYGON_TYPE;
-                FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
-            }
-            needed += sizeof(*pph);
-            point++;
-            while (point <= outline->contours[contour])
-            {
-                ppc = (TTPOLYCURVE *)((char *)pvBuf + needed);
-                type = (outline->tags[point] & FT_Curve_Tag_On) ?
-                       TT_PRIM_LINE : TT_PRIM_CSPLINE;
-                cpfx = 0;
-                do
-                {
-                    if (type == TT_PRIM_LINE)
-                    {
-                        if (pvBuf)
-                            FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
-                        cpfx++;
-                        point++;
-                    }
-                    else
-                    {
-                        /* Unlike QSPLINEs, CSPLINEs always have their endpoint
-                           so cpfx = 3n */
-
-                        /* FIXME: Possible optimization in endpoint calculation
-                           if there are two consecutive curves */
-                        cubic_control[0] = outline->points[point-1];
-                        if (!(outline->tags[point-1] & FT_Curve_Tag_On))
-                        {
-                            cubic_control[0].x += outline->points[point].x + 1;
-                            cubic_control[0].y += outline->points[point].y + 1;
-                            cubic_control[0].x >>= 1;
-                            cubic_control[0].y >>= 1;
-                        }
-                        if (point+1 > outline->contours[contour])
-                            cubic_control[3] = outline->points[first_pt];
-                        else
-                        {
-                            cubic_control[3] = outline->points[point+1];
-                            if (!(outline->tags[point+1] & FT_Curve_Tag_On))
-                            {
-                                cubic_control[3].x += outline->points[point].x + 1;
-                                cubic_control[3].y += outline->points[point].y + 1;
-                                cubic_control[3].x >>= 1;
-                                cubic_control[3].y >>= 1;
-                            }
-                        }
-                        /* r1 = 1/3 p0 + 2/3 p1
-                           r2 = 1/3 p2 + 2/3 p1 */
-                        cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
-                        cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
-                        cubic_control[2] = cubic_control[1];
-                        cubic_control[1].x += (cubic_control[0].x + 1) / 3;
-                        cubic_control[1].y += (cubic_control[0].y + 1) / 3;
-                        cubic_control[2].x += (cubic_control[3].x + 1) / 3;
-                        cubic_control[2].y += (cubic_control[3].y + 1) / 3;
-                        if (pvBuf)
-                        {
-                            FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
-                            FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
-                            FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
-                        }
-                        cpfx += 3;
-                        point++;
-                    }
-                }
-                while (point <= outline->contours[contour] &&
-                        (outline->tags[point] & FT_Curve_Tag_On) ==
-                        (outline->tags[point-1] & FT_Curve_Tag_On));
-                /* At the end of a contour Windows adds the start point,
-                   but only for Beziers and we've already done that. */
-                if (point <= outline->contours[contour] &&
-                        outline->tags[point] & FT_Curve_Tag_On)
-                {
-                    /* This is the closing pt of a bezier, but we've already
-                      added it, so just inc point and carry on */
-                    point++;
-                }
-                if (pvBuf)
-                {
-                    ppc->wType = type;
-                    ppc->cpfx = cpfx;
-                }
-                needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
-            }
-            if (pvBuf) pph->cb = needed - pph_start;
-        }
+        if (!pvBuf || !cjBuf)
+            break;
+        if (needed > cjBuf)
+            return GDI_ERROR;
+                                                
+        get_bezier_glyph_outline(outline, cjBuf, pvBuf);
         break;
     }
 
     default:
-        DPRINT1("Unsupported format %d\n", iFormat);
+        DPRINT1("Unsupported format %u\n", iFormat);
         return GDI_ERROR;
     }
 
-    DPRINT("ftGdiGetGlyphOutline END and needed %d\n", needed);
+    DPRINT("ftGdiGetGlyphOutline END and needed %lu\n", needed);
     return needed;
 }
 
@@ -2098,6 +2209,7 @@ TextIntGetTextExtentPoint(PDC dc,
     BOOL use_kerning;
     FT_Render_Mode RenderMode;
     BOOLEAN Render;
+    PMATRIX pmxWorldToDevice;
 
     FontGDI = ObjToGDI(TextObj->Font, FONT);
 
@@ -2149,9 +2261,13 @@ TextIntGetTextExtentPoint(PDC dc,
                                                           dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)));
     if (error)
     {
-        DPRINT1("Error in setting pixel sizes: %u\n", error);
+        DPRINT1("Error in setting pixel sizes: %d\n", error);
     }
 
+    /* Get the DC's world-to-device transformation matrix */
+    pmxWorldToDevice = DC_pmxWorldToDevice(dc);
+    FtSetCoordinateTransform(face, pmxWorldToDevice);
+
     use_kerning = FT_HAS_KERNING(face);
     previous = 0;
 
@@ -2163,21 +2279,26 @@ TextIntGetTextExtentPoint(PDC dc,
             glyph_index = FT_Get_Char_Index(face, *String);
 
         if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
-                                             TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)))
+                                             TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
+                                             pmxWorldToDevice)))
         {
             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);
+                DPRINT1("WARNING: Failed to load and render glyph! [index: %d]\n", glyph_index);
                 break;
             }
 
             glyph = face->glyph;
-            realglyph = ftGdiGlyphCacheSet(face, glyph_index,
-                                           TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight, glyph, RenderMode);
+            realglyph = ftGdiGlyphCacheSet(face,
+                                           glyph_index,
+                                           TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
+                                           pmxWorldToDevice,
+                                           glyph,
+                                           RenderMode);
             if (!realglyph)
             {
-                DPRINT1("Failed to render glyph! [index: %u]\n", glyph_index);
+                DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
                 break;
             }
         }
@@ -2321,7 +2442,7 @@ ftGdiGetTextCharsetInfo(
         }
     }
 Exit:
-    DPRINT("CharSet %d CodePage %d\n",csi.ciCharset, csi.ciACP);
+    DPRINT("CharSet %u CodePage %u\n", csi.ciCharset, csi.ciACP);
     return (MAKELONG(csi.ciACP, csi.ciCharset));
 }
 
@@ -2434,6 +2555,7 @@ ftGdiGetTextMetricsW(
                                    /* FIXME: Should set character height if neg */
                                    (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ?
                                    dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)));
+        FtSetCoordinateTransform(Face, DC_pmxWorldToDevice(dc));
         IntUnLockFreeType;
         if (0 != Error)
         {
@@ -2542,15 +2664,42 @@ GetFontScore(LOGFONTW *LogFont, PUNICODE_STRING FaceName, PFONTGDI FontGDI)
     Status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
     if (NT_SUCCESS(Status))
     {
+        static const UNICODE_STRING MarlettFaceNameW = RTL_CONSTANT_STRING(L"Marlett");
+        static const UNICODE_STRING SymbolFaceNameW = RTL_CONSTANT_STRING(L"Symbol");
+        static const UNICODE_STRING VGAFaceNameW = RTL_CONSTANT_STRING(L"VGA");
+
         if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
         {
             EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
             EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
         }
-        if (0 == RtlCompareUnicodeString(FaceName, &EntryFaceNameW, TRUE))
+
+        if (!RtlCompareUnicodeString(FaceName, &EntryFaceNameW, TRUE))
         {
             Score += 49;
         }
+
+        /* FIXME: this is a work around to counter weird fonts on weird places.
+           A proper fix would be to score fonts on more attributes than
+           the ones in this function */
+        if (!RtlCompareUnicodeString(&MarlettFaceNameW, &EntryFaceNameW, TRUE) &&
+            RtlCompareUnicodeString(&MarlettFaceNameW, FaceName, TRUE))
+        {
+            Score = 0;
+        }
+
+        if (!RtlCompareUnicodeString(&SymbolFaceNameW, &EntryFaceNameW, TRUE) &&
+            RtlCompareUnicodeString(&SymbolFaceNameW, FaceName, TRUE))
+        {
+            Score = 0;
+        }
+
+        if (!RtlCompareUnicodeString(&VGAFaceNameW, &EntryFaceNameW, TRUE) &&
+            RtlCompareUnicodeString(&VGAFaceNameW, FaceName, TRUE))
+        {
+            Score = 0;
+        }
+
         RtlFreeUnicodeString(&EntryFaceNameW);
     }
 
@@ -2584,7 +2733,7 @@ GetFontScore(LOGFONTW *LogFont, PUNICODE_STRING FaceName, PFONTGDI FontGDI)
         Score += 25;
     }
 
-    ExFreePool(Otm);
+    ExFreePoolWithTag(Otm, GDITAG_TEXT);
 
     return Score;
 }
@@ -2660,8 +2809,7 @@ SubstituteFontFamily(PUNICODE_STRING FaceName, UINT Level)
         return;
     }
 
-    if (SubstituteFontFamilyKey(FaceName, L"SysFontSubstitutes") ||
-            SubstituteFontFamilyKey(FaceName, L"FontSubstitutes"))
+    if (SubstituteFontFamilyKey(FaceName, L"FontSubstitutes"))
     {
         SubstituteFontFamily(FaceName, Level + 1);
     }
@@ -2850,7 +2998,7 @@ IntGdiGetFontResourceInfo(
     /* Get the full path name */
     if (!IntGetFullFileName(NameInfo1, Size, FileName))
     {
-        ExFreePool(NameInfo1);
+        ExFreePoolWithTag(NameInfo1, TAG_FINF);
         return FALSE;
     }
 
@@ -2858,7 +3006,7 @@ IntGdiGetFontResourceInfo(
     NameInfo2 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF);
     if (!NameInfo2)
     {
-        ExFreePool(NameInfo1);
+        ExFreePoolWithTag(NameInfo1, TAG_FINF);
         EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
         return FALSE;
     }
@@ -2888,7 +3036,7 @@ IntGdiGetFontResourceInfo(
     IntUnLockGlobalFonts;
 
     /* Free the buffers */
-    ExFreePool(NameInfo1);
+    ExFreePoolWithTag(NameInfo1, TAG_FINF);
     ExFreePool(NameInfo2);
 
     if (!bFound && dwType != 5)
@@ -3041,7 +3189,7 @@ NtGdiGetFontFamilyInfo(HDC Dc,
     if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, &FontListHead) )
     {
         IntUnLockGlobalFonts;
-        ExFreePool(Info);
+        ExFreePoolWithTag(Info, GDITAG_TEXT);
         return -1;
     }
     IntUnLockGlobalFonts;
@@ -3053,7 +3201,7 @@ NtGdiGetFontFamilyInfo(HDC Dc,
                                    &Win32Process->PrivateFontListHead))
     {
         IntUnLockProcessPrivateFonts(Win32Process);
-        ExFreePool(Info);
+        ExFreePoolWithTag(Info, GDITAG_TEXT);
         return -1;
     }
     IntUnLockProcessPrivateFonts(Win32Process);
@@ -3061,7 +3209,7 @@ NtGdiGetFontFamilyInfo(HDC Dc,
     /* Enumerate font families in the registry */
     if (! GetFontFamilyInfoForSubstitutes(&LogFont, Info, &Count, Size))
     {
-        ExFreePool(Info);
+        ExFreePoolWithTag(Info, GDITAG_TEXT);
         return -1;
     }
 
@@ -3072,17 +3220,35 @@ NtGdiGetFontFamilyInfo(HDC Dc,
                                 (Count < Size ? Count : Size) * sizeof(FONTFAMILYINFO));
         if (! NT_SUCCESS(Status))
         {
-            ExFreePool(Info);
+            ExFreePoolWithTag(Info, GDITAG_TEXT);
             EngSetLastError(ERROR_INVALID_PARAMETER);
             return -1;
         }
     }
 
-    ExFreePool(Info);
+    ExFreePoolWithTag(Info, GDITAG_TEXT);
 
     return Count;
 }
 
+FORCEINLINE
+LONG
+ScaleLong(LONG lValue, PFLOATOBJ pef)
+{
+    FLOATOBJ efTemp;
+
+    /* Check if we have scaling different from 1 */
+    if (!FLOATOBJ_Equal(pef, (PFLOATOBJ)&gef1))
+    {
+        /* Need to multiply */
+        FLOATOBJ_SetLong(&efTemp, lValue);
+        FLOATOBJ_Mul(&efTemp, pef);
+        lValue = FLOATOBJ_GetLong(&efTemp);
+    }
+
+    return lValue;
+}
+
 BOOL
 APIENTRY
 GreExtTextOutW(
@@ -3113,7 +3279,7 @@ GreExtTextOutW(
     LONGLONG TextLeft, RealXStart;
     ULONG TextTop, previous, BackgroundLeft;
     FT_Bool use_kerning;
-    RECTL DestRect, MaskRect, DummyRect = {0, 0, 0, 0};
+    RECTL DestRect, MaskRect;
     POINTL SourcePoint, BrushOrigin;
     HBITMAP HSourceGlyph;
     SURFOBJ *SourceGlyphSurf;
@@ -3129,6 +3295,9 @@ GreExtTextOutW(
     POINT Start;
     BOOL DoBreak = FALSE;
     USHORT DxShift;
+    PMATRIX pmxWorldToDevice;
+    LONG fixAscender, fixDescender;
+    FLOATOBJ Scale;
 
     // TODO: Write test-cases to exactly match real Windows in different
     // bad parameters (e.g. does Windows check the DC or the RECT first?).
@@ -3206,7 +3375,7 @@ GreExtTextOutW(
         DestRect.right  += dc->ptlDCOrig.x;
         DestRect.bottom += dc->ptlDCOrig.y;
 
-        DC_vPrepareDCsForBlit(dc, DestRect, NULL, DestRect);
+        DC_vPrepareDCsForBlit(dc, &DestRect, NULL, NULL);
 
         if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
             DC_vUpdateBackgroundBrush(dc);
@@ -3215,7 +3384,7 @@ GreExtTextOutW(
             &dc->dclevel.pSurface->SurfObj,
             NULL,
             NULL,
-            dc->rosdc.CombinedClip,
+            &dc->co.ClipObj,
             NULL,
             &DestRect,
             &SourcePoint,
@@ -3287,21 +3456,27 @@ GreExtTextOutW(
                 dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)));
     if (error)
     {
-        DPRINT1("Error in setting pixel sizes: %u\n", error);
+        DPRINT1("Error in setting pixel sizes: %d\n", error);
         IntUnLockFreeType;
         goto fail;
     }
 
+    pmxWorldToDevice = DC_pmxWorldToDevice(dc);
+    FtSetCoordinateTransform(face, pmxWorldToDevice);
+
     /*
      * Process the vertical alignment and determine the yoff.
      */
 
+    fixAscender = ScaleLong(face->size->metrics.ascender, &pmxWorldToDevice->efM22);
+    fixDescender = ScaleLong(face->size->metrics.descender, &pmxWorldToDevice->efM22);
+
     if (pdcattr->lTextAlign & TA_BASELINE)
         yoff = 0;
     else if (pdcattr->lTextAlign & TA_BOTTOM)
-        yoff = -face->size->metrics.descender >> 6;
+        yoff = -fixDescender >> 6;
     else /* TA_TOP */
-        yoff = face->size->metrics.ascender >> 6;
+        yoff = fixAscender >> 6;
 
     use_kerning = FT_HAS_KERNING(face);
     previous = 0;
@@ -3339,20 +3514,25 @@ GreExtTextOutW(
                 glyph_index = FT_Get_Char_Index(face, *TempText);
 
             if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
-                                                 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)))
+                                                 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
+                                                 pmxWorldToDevice)))
             {
                 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);
+                    DPRINT1("WARNING: Failed to load and render glyph! [index: %d]\n", glyph_index);
                 }
 
                 glyph = face->glyph;
-                realglyph = ftGdiGlyphCacheSet(face, glyph_index,
-                                               TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight, glyph, RenderMode);
+                realglyph = ftGdiGlyphCacheSet(face,
+                                               glyph_index,
+                                               TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
+                                               pmxWorldToDevice,
+                                               glyph,
+                                               RenderMode);
                 if (!realglyph)
                 {
-                    DPRINT1("Failed to render glyph! [index: %u]\n", glyph_index);
+                    DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
                     IntUnLockFreeType;
                     goto fail;
                 }
@@ -3389,7 +3569,7 @@ GreExtTextOutW(
     BackgroundLeft = (RealXStart + 32) >> 6;
 
     /* Lock blit with a dummy rect */
-    DC_vPrepareDCsForBlit(dc, DummyRect, NULL, DummyRect);
+    DC_vPrepareDCsForBlit(dc, NULL, NULL, NULL);
 
     psurf = dc->dclevel.pSurface ;
     if(!psurf) psurf = psurfDefaultBitmap;
@@ -3415,25 +3595,29 @@ GreExtTextOutW(
             glyph_index = FT_Get_Char_Index(face, *String);
 
         if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
-                                             TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)))
+                                             TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
+                                             pmxWorldToDevice)))
         {
             error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
             if (error)
             {
-                DPRINT1("Failed to load and render glyph! [index: %u]\n", glyph_index);
+                DPRINT1("Failed to load and render glyph! [index: %d]\n", glyph_index);
                 IntUnLockFreeType;
+                DC_vFinishBlit(dc, NULL);
                 goto fail2;
             }
             glyph = face->glyph;
             realglyph = ftGdiGlyphCacheSet(face,
                                            glyph_index,
                                            TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
+                                           pmxWorldToDevice,
                                            glyph,
                                            RenderMode);
             if (!realglyph)
             {
-                DPRINT1("Failed to render glyph! [index: %u]\n", glyph_index);
+                DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
                 IntUnLockFreeType;
+                DC_vFinishBlit(dc, NULL);
                 goto fail2;
             }
         }
@@ -3445,22 +3629,22 @@ GreExtTextOutW(
             FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
             TextLeft += delta.x;
         }
-        DPRINT("TextLeft: %d\n", TextLeft);
-        DPRINT("TextTop: %d\n", TextTop);
+        DPRINT("TextLeft: %I64d\n", TextLeft);
+        DPRINT("TextTop: %lu\n", TextTop);
         DPRINT("Advance: %d\n", realglyph->root.advance.x);
 
         if (fuOptions & ETO_OPAQUE)
         {
             DestRect.left = BackgroundLeft;
             DestRect.right = (TextLeft + (realglyph->root.advance.x >> 10) + 32) >> 6;
-            DestRect.top = TextTop + yoff - ((face->size->metrics.ascender + 32) >> 6);
-            DestRect.bottom = TextTop + yoff + ((32 - face->size->metrics.descender) >> 6);
+            DestRect.top = TextTop + yoff - ((fixAscender + 32) >> 6);
+            DestRect.bottom = TextTop + yoff + ((32 - fixDescender) >> 6);
             MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
             IntEngBitBlt(
                 &psurf->SurfObj,
                 NULL,
                 NULL,
-                dc->rosdc.CombinedClip,
+                &dc->co.ClipObj,
                 NULL,
                 &DestRect,
                 &SourcePoint,
@@ -3497,6 +3681,7 @@ GreExtTextOutW(
             DPRINT1("WARNING: EngLockSurface() failed!\n");
             // FT_Done_Glyph(realglyph);
             IntUnLockFreeType;
+            DC_vFinishBlit(dc, NULL);
             goto fail2;
         }
         SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);
@@ -3505,6 +3690,7 @@ GreExtTextOutW(
             EngDeleteSurface((HSURF)HSourceGlyph);
             DPRINT1("WARNING: EngLockSurface() failed!\n");
             IntUnLockFreeType;
+            DC_vFinishBlit(dc, NULL);
             goto fail2;
         }
 
@@ -3531,7 +3717,7 @@ GreExtTextOutW(
         IntEngMaskBlt(
             SurfObj,
             SourceGlyphSurf,
-            dc->rosdc.CombinedClip,
+            &dc->co.ClipObj,
             &exloRGB2Dst.xlo,
             &exloDst2RGB.xlo,
             &DestRect,
@@ -3551,12 +3737,18 @@ GreExtTextOutW(
         if (NULL == Dx)
         {
             TextLeft += realglyph->root.advance.x >> 10;
-             DPRINT("New TextLeft: %d\n", TextLeft);
+             DPRINT("New TextLeft: %I64d\n", TextLeft);
         }
         else
         {
-            TextLeft += Dx[i<<DxShift] << 6;
-             DPRINT("New TextLeft2: %d\n", TextLeft);
+            // FIXME this should probably be a matrix transform with TextTop as well.
+            Scale = pdcattr->mxWorldToDevice.efM11;
+            if (_FLOATOBJ_Equal0(&Scale))
+                FLOATOBJ_Set1(&Scale);
+            FLOATOBJ_MulLong(&Scale, Dx[i<<DxShift] << 6); // do the shift before multiplying to preserve precision
+            TextLeft += FLOATOBJ_GetLong(&Scale);
+            DPRINT("New TextLeft2: %I64d\n", TextLeft);
         }
 
         if (DxShift)
@@ -3739,6 +3931,7 @@ NtGdiGetCharABCWidthsW(
     UINT i, glyph_index, BufferSize;
     HFONT hFont = 0;
     NTSTATUS Status = STATUS_SUCCESS;
+    PMATRIX pmxWorldToDevice;
 
     if (pwch)
     {
@@ -3778,18 +3971,21 @@ NtGdiGetCharABCWidthsW(
     dc = DC_LockDc(hDC);
     if (dc == NULL)
     {
-        ExFreePool(SafeBuff);
+        ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
         EngSetLastError(ERROR_INVALID_HANDLE);
         return FALSE;
     }
     pdcattr = dc->pdcattr;
     hFont = pdcattr->hlfntNew;
     TextObj = RealizeFontInit(hFont);
+
+    /* Get the DC's world-to-device transformation matrix */
+    pmxWorldToDevice = DC_pmxWorldToDevice(dc);
     DC_UnlockDc(dc);
 
     if (TextObj == NULL)
     {
-        ExFreePool(SafeBuff);
+        ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
         EngSetLastError(ERROR_INVALID_HANDLE);
         return FALSE;
     }
@@ -3812,7 +4008,7 @@ NtGdiGetCharABCWidthsW(
         if (!found)
         {
             DPRINT1("WARNING: Could not find desired charmap!\n");
-            ExFreePool(SafeBuff);
+            ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
             EngSetLastError(ERROR_INVALID_HANDLE);
             return FALSE;
         }
@@ -3828,6 +4024,7 @@ NtGdiGetCharABCWidthsW(
                        /* FIXME: Should set character height if neg */
                        (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ?
                        dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)));
+    FtSetCoordinateTransform(face, pmxWorldToDevice);
 
     for (i = FirstChar; i < FirstChar+Count; i++)
     {
@@ -3880,10 +4077,10 @@ NtGdiGetCharABCWidthsW(
     if (! NT_SUCCESS(Status))
     {
         SetLastNtError(Status);
-        ExFreePool(SafeBuff);
+        ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
         return FALSE;
     }
-    ExFreePool(SafeBuff);
+    ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
     DPRINT("NtGdiGetCharABCWidths Worked!\n");
     return TRUE;
 }
@@ -3912,6 +4109,7 @@ NtGdiGetCharWidthW(
     FT_CharMap charmap, found = NULL;
     UINT i, glyph_index, BufferSize;
     HFONT hFont = 0;
+    PMATRIX pmxWorldToDevice;
 
     if (pwc)
     {
@@ -3945,18 +4143,20 @@ NtGdiGetCharWidthW(
     dc = DC_LockDc(hDC);
     if (dc == NULL)
     {
-        ExFreePool(SafeBuff);
+        ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
         EngSetLastError(ERROR_INVALID_HANDLE);
         return FALSE;
     }
     pdcattr = dc->pdcattr;
     hFont = pdcattr->hlfntNew;
     TextObj = RealizeFontInit(hFont);
+    /* Get the DC's world-to-device transformation matrix */
+    pmxWorldToDevice = DC_pmxWorldToDevice(dc);
     DC_UnlockDc(dc);
 
     if (TextObj == NULL)
     {
-        ExFreePool(SafeBuff);
+        ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
         EngSetLastError(ERROR_INVALID_HANDLE);
         return FALSE;
     }
@@ -3995,6 +4195,7 @@ NtGdiGetCharWidthW(
                        /* FIXME: Should set character height if neg */
                        (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ?
                        dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)));
+    FtSetCoordinateTransform(face, pmxWorldToDevice);
 
     for (i = FirstChar; i < FirstChar+Count; i++)
     {
@@ -4021,7 +4222,7 @@ NtGdiGetCharWidthW(
     IntUnLockFreeType;
     TEXTOBJ_UnlockText(TextObj);
     MmCopyToCaller(Buffer, SafeBuff, BufferSize);
-    ExFreePool(SafeBuff);
+    ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
     return TRUE;
 }
 
@@ -4088,7 +4289,7 @@ GreGetGlyphIndicesW(
         }
         IntGetOutlineTextMetrics(FontGDI, Size, potm);
         DefChar = potm->otmTextMetrics.tmDefaultChar; // May need this.
-        ExFreePool(potm);
+        ExFreePoolWithTag(potm, GDITAG_TEXT);
     }
 
     IntLockFreeType;
@@ -4183,7 +4384,7 @@ NtGdiGetGlyphIndicesW(
         }
         IntGetOutlineTextMetrics(FontGDI, Size, potm);
         DefChar = potm->otmTextMetrics.tmDefaultChar; // May need this.
-        ExFreePool(potm);
+        ExFreePoolWithTag(potm, GDITAG_TEXT);
     }
 
     _SEH2_TRY