Implement ExtTextOut on an open path

Dmitry Timoshkov dmitry at baikal.ru
Mon Aug 22 10:05:46 CDT 2005


Hello,

Changelog:
    Dmitry Timoshkov <dmitry at codeweavers.com>
    Implement ExtTextOut on an open path.

diff -up cvs/hq/wine/dlls/gdi/font.c wine/dlls/gdi/font.c
--- cvs/hq/wine/dlls/gdi/font.c	2005-08-22 11:43:25.000000000 +0900
+++ wine/dlls/gdi/font.c	2005-08-22 21:15:47.000000000 +0900
@@ -1727,7 +1727,7 @@ BOOL WINAPI ExtTextOutW( HDC hdc, INT x,
             FIXME("flags ETO_NUMERICSLOCAL|ETO_NUMERICSLATIN|ETO_PDY unimplemented\n");
 
         if(PATH_IsPathOpen(dc->path))
-            FIXME("called on an open path\n");
+            ret = PATH_ExtTextOut(dc, x, y, flags, lprect, str, count, lpDx);
         else if(dc->funcs->pExtTextOut)
         {
             if( !(flags&(ETO_GLYPH_INDEX|ETO_IGNORELANGUAGE)) && BidiAvail && count>0 )
diff -up cvs/hq/wine/dlls/gdi/gdi_private.h wine/dlls/gdi/gdi_private.h
--- cvs/hq/wine/dlls/gdi/gdi_private.h	2005-04-15 20:45:01.000000000 +0900
+++ wine/dlls/gdi/gdi_private.h	2005-08-22 21:15:53.000000000 +0900
@@ -404,6 +404,8 @@ extern BOOL PATH_AssignGdiPath(GdiPath *
 extern BOOL PATH_MoveTo(DC *dc);
 extern BOOL PATH_LineTo(DC *dc, INT x, INT y);
 extern BOOL PATH_Rectangle(DC *dc, INT x1, INT y1, INT x2, INT y2);
+extern BOOL PATH_ExtTextOut(DC *dc, INT x, INT y, UINT flags, const RECT *lprc,
+                            LPCWSTR str, UINT count, const INT *dx);
 extern BOOL PATH_Ellipse(DC *dc, INT x1, INT y1, INT x2, INT y2);
 extern BOOL PATH_Arc(DC *dc, INT x1, INT y1, INT x2, INT y2,
                      INT xStart, INT yStart, INT xEnd, INT yEnd, INT lines);
diff -up cvs/hq/wine/dlls/gdi/path.c wine/dlls/gdi/path.c
--- cvs/hq/wine/dlls/gdi/path.c	2005-05-17 15:08:29.000000000 +0900
+++ wine/dlls/gdi/path.c	2005-08-22 23:59:34.000000000 +0900
@@ -3,6 +3,7 @@
  *
  * Copyright 1997, 1998 Martin Boehme
  *                 1999 Huw D M Davies
+ * Copyright 2005 Dmitry Timoshkov
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -26,6 +27,7 @@
 #include <math.h>
 #include <stdarg.h>
 #include <string.h>
+#include <stdlib.h>
 #if defined(HAVE_FLOAT_H)
 #include <float.h>
 #endif
@@ -1210,6 +1212,376 @@ static BOOL PATH_PathToRegion(GdiPath *p
    return TRUE;
 }
 
+static inline INT int_from_fixed(FIXED f)
+{
+    return (f.fract >= 0x8000) ? (f.value + 1) : f.value;
+}
+
+static void TT_BezierTo(GdiPath *pPath, POINT *lppt, INT n)
+{
+    if (n < 2) return;
+
+    if (n == 2)
+    {
+        PATH_AddEntry(pPath, &lppt[1], PT_LINETO);
+    }
+    else if (n == 3)
+    {
+        PATH_AddEntry(pPath, &lppt[0], PT_BEZIERTO);
+        PATH_AddEntry(pPath, &lppt[1], PT_BEZIERTO);
+        PATH_AddEntry(pPath, &lppt[2], PT_BEZIERTO);
+    }
+    else
+    {
+        POINT pt[3];
+        INT i = 0;
+
+        pt[2] = lppt[0];
+        n--;
+
+        while (n > 2)
+        {
+            pt[0] = pt[2];
+            pt[1] = lppt[i+1];
+            pt[2].x = (lppt[i+2].x + lppt[i+1].x) / 2;
+            pt[2].y = (lppt[i+2].y + lppt[i+1].y) / 2;
+            TT_BezierTo(pPath, pt, 3);
+            n--;
+            i++;
+        }
+
+        pt[0] = pt[2];
+        pt[1] = lppt[i+1];
+        pt[2] = lppt[i+2];
+        TT_BezierTo(pPath, pt, 3);
+    }
+}
+
+static BOOL PATH_add_outline(DC *dc, INT x, INT y, TTPOLYGONHEADER *header, DWORD size)
+{
+    GdiPath *pPath = &dc->path;
+    TTPOLYGONHEADER *start;
+    POINT pt;
+
+    start = header;
+
+    while ((char *)header < (char *)start + size)
+    {
+        TTPOLYCURVE *curve;
+
+        if (header->dwType != TT_POLYGON_TYPE)
+        {
+            FIXME("Unknown header type %ld\n", header->dwType);
+            return FALSE;
+        }
+
+        pt.x = x + int_from_fixed(header->pfxStart.x);
+        pt.y = y - int_from_fixed(header->pfxStart.y);
+        LPtoDP(dc->hSelf, &pt, 1);
+        PATH_AddEntry(pPath, &pt, PT_MOVETO);
+
+        curve = (TTPOLYCURVE *)(header + 1);
+
+        while ((char *)curve < (char *)header + header->cb)
+        {
+            /*TRACE("curve->wType %d\n", curve->wType);*/
+
+            switch(curve->wType)
+            {
+            case TT_PRIM_LINE:
+            {
+                WORD i;
+                POINT *pt = HeapAlloc(GetProcessHeap(), 0, curve->cpfx * sizeof(POINT));
+
+                if (!pt) return FALSE;
+
+                for (i = 0; i < curve->cpfx; i++)
+                {
+                    pt[i].x = x + int_from_fixed(curve->apfx[i].x);
+                    pt[i].y = y - int_from_fixed(curve->apfx[i].y);
+                    LPtoDP(dc->hSelf, &pt[i], 1);
+                    PATH_AddEntry(pPath, &pt[i], PT_LINETO);
+                }
+
+                HeapFree(GetProcessHeap(), 0, pt);
+                break;
+            }
+
+            case TT_PRIM_QSPLINE:
+            case TT_PRIM_CSPLINE:
+            {
+                WORD i;
+                POINTFX ptfx;
+                POINT *pt = HeapAlloc(GetProcessHeap(), 0, (curve->cpfx + 1) * sizeof(POINT));
+
+                if (!pt) return FALSE;
+
+                ptfx = *(POINTFX *)((char *)curve - sizeof(POINTFX));
+
+                pt[0].x = x + int_from_fixed(ptfx.x);
+                pt[0].y = y - int_from_fixed(ptfx.y);
+                LPtoDP(dc->hSelf, &pt[0], 1);
+
+                for(i = 0; i < curve->cpfx; i++)
+                {
+                    pt[i + 1].x = x + int_from_fixed(curve->apfx[i].x);
+                    pt[i + 1].y = y - int_from_fixed(curve->apfx[i].y);
+                    LPtoDP(dc->hSelf, &pt[i + 1], 1);
+                }
+
+                TT_BezierTo(pPath, pt, curve->cpfx + 1);
+
+                HeapFree(GetProcessHeap(), 0, pt);
+                break;
+            }
+
+            default:
+                FIXME("Unknown curve type %04x\n", curve->wType);
+                return FALSE;
+            }
+
+            curve = (TTPOLYCURVE *)&curve->apfx[curve->cpfx];
+        }
+
+        header = (TTPOLYGONHEADER *)((char *)header + header->cb);
+    }
+
+    return CloseFigure(dc->hSelf);
+}
+
+/*
+ * PATH_ExtTextOut, mostly copied from xrender.c
+ */
+BOOL PATH_ExtTextOut(DC *dc, INT x, INT y, UINT flags, const RECT *lprc,
+                     LPCWSTR str, UINT count, const INT *dx)
+{
+    unsigned int idx;
+    TEXTMETRICW tm;
+    SIZE sz;
+    RECT rc;
+    BOOL done_extents = FALSE;
+    LONG width, xwidth, ywidth;
+    double cosEsc, sinEsc;
+    LOGFONTW lf;
+    WORD *glyphs;
+    POINT pt, org;
+    BOOL retv = FALSE;
+    HDC hdc = dc->hSelf;
+    INT *deltas = NULL, char_extra;
+    UINT align = GetTextAlign( hdc );
+
+    TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc, x, y, flags,
+	  wine_dbgstr_rect(lprc), debugstr_wn(str, count), count, dx);
+
+    if (!count) return TRUE;
+
+    if (flags & ETO_GLYPH_INDEX)
+        glyphs = (WORD *)str;
+    else
+    {
+        glyphs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR));
+        GetGlyphIndicesW(hdc, str, count, (WORD *)glyphs, 0);
+    }
+
+    TRACE("align = %x bkmode = %x mapmode = %x\n", align, GetBkMode(hdc), GetMapMode(hdc));
+
+    if (align & TA_UPDATECP)
+    {
+        GetCurrentPositionEx(hdc, &pt);
+        x = pt.x;
+        y = pt.y;
+    }
+
+    GetTextMetricsW(hdc, &tm);
+    GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
+
+    if (lf.lfEscapement != 0)
+    {
+        cosEsc = cos(lf.lfEscapement * M_PI / 1800);
+        sinEsc = sin(lf.lfEscapement * M_PI / 1800);
+    } else
+    {
+        cosEsc = 1;
+        sinEsc = 0;
+    }
+
+    if (flags & (ETO_CLIPPED | ETO_OPAQUE))
+    {
+        if (!lprc)
+        {
+            if (flags & ETO_CLIPPED) goto done;
+
+            GetTextExtentPointI(hdc, glyphs, count, &sz);
+            done_extents = TRUE;
+            rc.left = x;
+            rc.top = y;
+            rc.right = x + sz.cx;
+            rc.bottom = y + sz.cy;
+        }
+        else
+            rc = *lprc;
+
+        LPtoDP(hdc, (POINT *)&rc, 2);
+
+        if (rc.left > rc.right) {INT tmp = rc.left; rc.left = rc.right; rc.right = tmp;}
+        if (rc.top > rc.bottom) {INT tmp = rc.top; rc.top = rc.bottom; rc.bottom = tmp;}
+    }
+
+    pt.x = x;
+    pt.y = y;
+    LPtoDP(hdc, &pt, 1);
+    x = pt.x;
+    y = pt.y;
+
+    TRACE("real x,y %d,%d\n", x, y);
+
+    char_extra = GetTextCharacterExtra(hdc);
+    if (char_extra)
+    {
+        UINT i;
+        SIZE tmpsz;
+
+        deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT));
+
+        for (i = 0; i < count; i++)
+        {
+            if (dx)
+                deltas[i] = dx[i] + char_extra;
+            else
+            {
+                GetTextExtentPointI(hdc, glyphs + i, 1, &tmpsz);
+                deltas[i] = tmpsz.cx;
+            }
+        }
+    }
+    else if (dx)
+        deltas = (INT *)dx;
+
+    if (deltas)
+    {
+        width = 0;
+        for (idx = 0; idx < count; idx++)
+            width += deltas[idx];
+    }
+    else
+    {
+        if (!done_extents)
+        {
+            GetTextExtentPointI(hdc, glyphs, count, &sz);
+            done_extents = TRUE;
+        }
+        width = sz.cx;
+    }
+
+    INTERNAL_WSTODS(dc, &width);
+    xwidth = width * cosEsc;
+    ywidth = width * sinEsc;
+
+    INTERNAL_WSTODS(dc, &tm.tmAscent);
+    tm.tmAscent = abs(tm.tmAscent);
+    INTERNAL_WSTODS(dc, &tm.tmDescent);
+    tm.tmDescent = abs(tm.tmDescent);
+    switch (align & (TA_LEFT | TA_RIGHT | TA_CENTER))
+    {
+    case TA_LEFT:
+        if (align & TA_UPDATECP)
+        {
+            pt.x = x + xwidth;
+            pt.y = y - ywidth;
+            DPtoLP(hdc, &pt, 1);
+            MoveToEx(hdc, pt.x, pt.y, NULL);
+        }
+        break;
+
+    case TA_CENTER:
+        x -= xwidth / 2;
+        y += ywidth / 2;
+        break;
+
+    case TA_RIGHT:
+        x -= xwidth;
+        y += ywidth;
+        if (align & TA_UPDATECP)
+        {
+            pt.x = x;
+            pt.y = y;
+            DPtoLP(hdc, &pt, 1);
+            MoveToEx(hdc, pt.x, pt.y, NULL);
+	}
+        break;
+    }
+
+    switch (align & (TA_TOP | TA_BOTTOM | TA_BASELINE))
+    {
+    case TA_TOP:
+        y += tm.tmAscent * cosEsc;
+        x += tm.tmAscent * sinEsc;
+        break;
+
+    case TA_BOTTOM:
+        y -= tm.tmDescent * cosEsc;
+        x -= tm.tmDescent * sinEsc;
+        break;
+
+    case TA_BASELINE:
+        break;
+    }
+
+    if (flags & ETO_CLIPPED)
+        FIXME("ETO_CLIPPED not handled\n");
+
+    GetDCOrgEx(hdc, &org);
+
+    for (idx = 0; idx < count; idx++)
+    {
+        INT offset = 0, xoff = 0, yoff = 0;
+        GLYPHMETRICS gm;
+        DWORD dwSize;
+        void *outline;
+        static const UINT ggo_format = GGO_GLYPH_INDEX | GGO_NATIVE;
+
+        dwSize = GetGlyphOutlineW(hdc, glyphs[idx], ggo_format, &gm, 0, NULL, NULL);
+        if (!dwSize) goto done;
+
+        outline = HeapAlloc(GetProcessHeap(), 0, dwSize);
+        if (!outline) goto done;
+
+        GetGlyphOutlineW(hdc, glyphs[idx], ggo_format, &gm, dwSize, outline, NULL);
+
+        PATH_add_outline(dc, org.x + x + xoff, org.x + y + yoff, outline, dwSize);
+
+        HeapFree(GetProcessHeap(), 0, outline);
+
+        if (deltas)
+        {
+            LONG delta = deltas[idx];
+            INTERNAL_WSTODS(dc, &delta);
+            offset += delta;
+            xoff = offset * cosEsc;
+            yoff = offset * -sinEsc;
+        }
+        else
+        {
+            xoff += gm.gmCellIncX;
+            yoff += gm.gmCellIncY;
+        }
+    }
+
+    if (deltas && deltas != dx)
+        HeapFree(GetProcessHeap(), 0, deltas);
+
+    if (flags & ETO_CLIPPED)
+    {
+        /* FIXME: restore the device region */
+    }
+
+    retv = TRUE;
+
+done:
+    if(glyphs != str) HeapFree(GetProcessHeap(), 0, (WORD*)glyphs);
+    return retv;
+}
+
 /* PATH_EmptyPath
  *
  * Removes all entries from the path and sets the path state to PATH_Null.






More information about the wine-patches mailing list