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