First draft of ExtTextOut on an open path
Dmitry Timoshkov
dmitry at baikal.ru
Sat Nov 5 05:48:55 CST 2005
Hello,
there are some things which need additional work to make it look
exactly like in windows, but most of the functionality is there.
I've added a couple of tests to see how it works on metafiles.
Changelog:
Dmitry Timoshkov <dmitry at codeweavers.com>
First draft of ExtTextOut on an open path.
diff -up cvs/hq/wine/dlls/gdi/enhmfdrv/graphics.c wine/dlls/gdi/enhmfdrv/graphics.c
--- cvs/hq/wine/dlls/gdi/enhmfdrv/graphics.c 2005-08-23 23:02:55.000000000 +0900
+++ wine/dlls/gdi/enhmfdrv/graphics.c 2005-11-05 19:06:51.000000000 +0800
@@ -722,7 +722,8 @@ BOOL EMFDRV_ExtTextOut( PHYSDEV dev, INT
nSize = sizeof(*pemr) + ((count+1) & ~1) * sizeof(WCHAR) + count * sizeof(INT);
- TRACE("%s count %d nSize = %ld\n", debugstr_wn(str, count), count, nSize);
+ TRACE("%s %s count %d nSize = %ld\n", debugstr_wn(str, count),
+ wine_dbgstr_rect(lprect), count, nSize);
pemr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nSize);
pemr->emr.iType = EMR_EXTTEXTOUTW;
diff -up cvs/hq/wine/dlls/gdi/font.c wine/dlls/gdi/font.c
--- cvs/hq/wine/dlls/gdi/font.c 2005-10-31 15:27:03.000000000 +0800
+++ wine/dlls/gdi/font.c 2005-11-05 18:00:21.000000000 +0800
@@ -1757,14 +1757,7 @@ BOOL WINAPI ExtTextOutW( HDC hdc, INT x,
if (flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN | ETO_PDY))
FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN | ETO_PDY unimplemented\n");
- if(PATH_IsPathOpen(dc->path))
- {
- FIXME("called on an open path\n");
- GDI_ReleaseObj( hdc );
- return ret;
- }
-
- if(!dc->funcs->pExtTextOut)
+ if (!dc->funcs->pExtTextOut && !PATH_IsPathOpen(dc->path))
{
GDI_ReleaseObj( hdc );
return ret;
@@ -1852,7 +1845,7 @@ BOOL WINAPI ExtTextOutW( HDC hdc, INT x,
if(rc.top > rc.bottom) {INT tmp = rc.top; rc.top = rc.bottom; rc.bottom = tmp;}
}
- if(flags & ETO_OPAQUE)
+ if ((flags & ETO_OPAQUE) && !PATH_IsPathOpen(dc->path))
dc->funcs->pExtTextOut(dc->physDev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
if(count == 0)
@@ -1959,7 +1952,7 @@ BOOL WINAPI ExtTextOutW( HDC hdc, INT x,
break;
}
- if(GetBkMode(hdc) != TRANSPARENT)
+ if (GetBkMode(hdc) != TRANSPARENT && !PATH_IsPathOpen(dc->path))
{
if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
{
@@ -2010,7 +2003,12 @@ BOOL WINAPI ExtTextOutW( HDC hdc, INT x,
}
if(span)
{
- dc->funcs->pExtTextOut(dc->physDev, x + offsets[i - span] * cosEsc, y - offsets[i - span] * sinEsc,
+ if (PATH_IsPathOpen(dc->path))
+ ret = PATH_ExtTextOut(dc, x + offsets[i - span] * cosEsc, y - offsets[i - span] * sinEsc,
+ (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
+ glyphs, span, deltas ? deltas + i - span : NULL);
+ else
+ dc->funcs->pExtTextOut(dc->physDev, x + offsets[i - span] * cosEsc, y - offsets[i - span] * sinEsc,
(flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
glyphs, span, deltas ? deltas + i - span : NULL);
span = 0;
@@ -2021,7 +2019,13 @@ BOOL WINAPI ExtTextOutW( HDC hdc, INT x,
if(i == count - 1)
{
- ret = dc->funcs->pExtTextOut(dc->physDev, x + (offsets ? offsets[count - span] * cosEsc : 0),
+ if (PATH_IsPathOpen(dc->path))
+ ret = PATH_ExtTextOut(dc, x + (offsets ? offsets[count - span] * cosEsc : 0),
+ y - (offsets ? offsets[count - span] * sinEsc : 0),
+ (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
+ glyphs, span, deltas ? deltas + count - span : NULL);
+ else
+ ret = dc->funcs->pExtTextOut(dc->physDev, x + (offsets ? offsets[count - span] * cosEsc : 0),
y - (offsets ? offsets[count - span] * sinEsc : 0),
(flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
glyphs, span, deltas ? deltas + count - span : NULL);
@@ -2038,7 +2042,12 @@ BOOL WINAPI ExtTextOutW( HDC hdc, INT x,
GetGlyphIndicesW(hdc, reordered_str, count, glyphs, 0);
flags |= ETO_GLYPH_INDEX;
}
- ret = dc->funcs->pExtTextOut(dc->physDev, x, y, (flags & ~ETO_OPAQUE), &rc,
+
+ if (PATH_IsPathOpen(dc->path))
+ ret = PATH_ExtTextOut(dc, x, y, (flags & ~ETO_OPAQUE), &rc,
+ glyphs ? glyphs : reordered_str, count, deltas);
+ else
+ ret = dc->funcs->pExtTextOut(dc->physDev, x, y, (flags & ~ETO_OPAQUE), &rc,
glyphs ? glyphs : reordered_str, count, deltas);
}
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-09-07 22:43:36.000000000 +0900
+++ wine/dlls/gdi/gdi_private.h 2005-11-05 18:01:08.000000000 +0800
@@ -405,6 +405,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-08-23 23:02:55.000000000 +0900
+++ wine/dlls/gdi/path.c 2005-11-05 19:13:22.000000000 +0800
@@ -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,208 @@ 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;
+}
+
+/**********************************************************************
+ * PATH_BezierTo
+ *
+ * internally used by PATH_add_outline
+ */
+static void PATH_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;
+ PATH_BezierTo(pPath, pt, 3);
+ n--;
+ i++;
+ }
+
+ pt[0] = pt[2];
+ pt[1] = lppt[i+1];
+ pt[2] = lppt[i+2];
+ PATH_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;
+
+ for (i = 0; i < curve->cpfx; i++)
+ {
+ pt.x = x + int_from_fixed(curve->apfx[i].x);
+ pt.y = y - int_from_fixed(curve->apfx[i].y);
+ LPtoDP(dc->hSelf, &pt, 1);
+ PATH_AddEntry(pPath, &pt, PT_LINETO);
+ }
+ break;
+ }
+
+ case TT_PRIM_QSPLINE:
+ case TT_PRIM_CSPLINE:
+ {
+ WORD i;
+ POINTFX ptfx;
+ POINT *pts = HeapAlloc(GetProcessHeap(), 0, (curve->cpfx + 1) * sizeof(POINT));
+
+ if (!pts) return FALSE;
+
+ ptfx = *(POINTFX *)((char *)curve - sizeof(POINTFX));
+
+ pts[0].x = x + int_from_fixed(ptfx.x);
+ pts[0].y = y - int_from_fixed(ptfx.y);
+ LPtoDP(dc->hSelf, &pts[0], 1);
+
+ for(i = 0; i < curve->cpfx; i++)
+ {
+ pts[i + 1].x = x + int_from_fixed(curve->apfx[i].x);
+ pts[i + 1].y = y - int_from_fixed(curve->apfx[i].y);
+ LPtoDP(dc->hSelf, &pts[i + 1], 1);
+ }
+
+ PATH_BezierTo(pPath, pts, curve->cpfx + 1);
+
+ HeapFree(GetProcessHeap(), 0, pts);
+ 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
+ */
+BOOL PATH_ExtTextOut(DC *dc, INT x, INT y, UINT flags, const RECT *lprc,
+ LPCWSTR str, UINT count, const INT *dx)
+{
+ unsigned int idx;
+ double cosEsc, sinEsc;
+ LOGFONTW lf;
+ POINT org;
+ HDC hdc = dc->hSelf;
+
+ 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;
+
+ 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;
+ }
+
+ GetDCOrgEx(hdc, &org);
+
+ for (idx = 0; idx < count; idx++)
+ {
+ INT offset = 0, xoff = 0, yoff = 0;
+ GLYPHMETRICS gm;
+ DWORD dwSize;
+ void *outline;
+
+ dwSize = GetGlyphOutlineW(hdc, str[idx], GGO_GLYPH_INDEX | GGO_NATIVE, &gm, 0, NULL, NULL);
+ if (!dwSize) return FALSE;
+
+ outline = HeapAlloc(GetProcessHeap(), 0, dwSize);
+ if (!outline) return FALSE;
+
+ GetGlyphOutlineW(hdc, str[idx], GGO_GLYPH_INDEX | GGO_NATIVE, &gm, dwSize, outline, NULL);
+
+ PATH_add_outline(dc, org.x + x + xoff, org.x + y + yoff, outline, dwSize);
+
+ HeapFree(GetProcessHeap(), 0, outline);
+
+ if (dx)
+ {
+ offset += dx[idx];
+ xoff = offset * cosEsc;
+ yoff = offset * -sinEsc;
+ }
+ else
+ {
+ xoff += gm.gmCellIncX;
+ yoff += gm.gmCellIncY;
+ }
+ }
+ return TRUE;
+}
+
/* PATH_EmptyPath
*
* Removes all entries from the path and sets the path state to PATH_Null.
diff -up cvs/hq/wine/dlls/gdi/tests/metafile.c wine/dlls/gdi/tests/metafile.c
--- cvs/hq/wine/dlls/gdi/tests/metafile.c 2005-11-02 20:09:12.000000000 +0800
+++ wine/dlls/gdi/tests/metafile.c 2005-11-05 19:37:44.000000000 +0800
@@ -422,6 +422,63 @@ static const unsigned char MF_PATTERN_BR
0x00, 0x00
};
+static const unsigned char MF_TEXTOUT_ON_PATH_BITS[] =
+{
+ 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x19, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x32, 0x0a,
+ 0x16, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x54, 0x65, 0x73, 0x74, 0x03, 0x00, 0x05, 0x00,
+ 0x08, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00
+};
+
+static const unsigned char EMF_TEXTOUT_ON_PATH_BITS[] =
+{
+ 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xe7, 0xff, 0xff, 0xff, 0xe9, 0xff, 0xff, 0xff,
+ 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
+ 0xf4, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+ 0x40, 0x01, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x04, 0x00,
+ 0x80, 0xa9, 0x03, 0x00, 0x3b, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
+ 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc8, 0x41, 0x00, 0x80, 0xbb, 0x41,
+ 0x0b, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x54, 0x00, 0x00, 0x00,
+ 0x54, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
+ 0x3c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x00, 0x00
+};
+
+/* For debugging or dumping the raw metafiles produced by
+ * new test functions.
+ */
+static INT CALLBACK mf_enum_proc(HDC hdc, HANDLETABLE *ht, METARECORD *mr,
+ INT nobj, LPARAM param)
+{
+ trace("hdc %p, mr->rdFunction %d, mr->rdSize %lu, param %p\n",
+ hdc, mr->rdFunction, mr->rdSize, (void *)param);
+ return TRUE;
+}
+
/* For debugging or dumping the raw metafiles produced by
* new test functions.
*/
@@ -521,6 +578,101 @@ static int compare_mf_disk_bits(LPCSTR n
return diff;
}
+/* For debugging or dumping the raw EMFs produced by
+ * new test functions.
+ */
+static void dump_emf_bits(const HENHMETAFILE mf, const char *desc)
+{
+ BYTE buf[MF_BUFSIZE];
+ UINT mfsize, i;
+
+ mfsize = GetEnhMetaFileBits(mf, MF_BUFSIZE, buf);
+ ok (mfsize > 0, "%s: GetEnhMetaFileBits failed\n", desc);
+
+ printf("EMF %s has bits:\n{\n ", desc);
+ for (i = 0; i < mfsize; i++)
+ {
+ printf ("0x%02x", buf[i]);
+ if (i == mfsize-1)
+ printf ("\n");
+ else if (i % 8 == 7)
+ printf (",\n ");
+ else
+ printf (", ");
+ }
+ printf ("};\n");
+}
+
+static void dump_emf_records(const HENHMETAFILE mf, const char *desc)
+{
+ BYTE *emf;
+ BYTE buf[MF_BUFSIZE];
+ UINT mfsize, offset;
+
+ mfsize = GetEnhMetaFileBits(mf, MF_BUFSIZE, buf);
+ ok (mfsize > 0, "%s: GetEnhMetaFileBits failed\n", desc);
+
+ printf("EMF %s has records:\n", desc);
+
+ emf = buf;
+ offset = 0;
+ while(offset < mfsize)
+ {
+ EMR *emr = (EMR *)(emf + offset);
+ trace("emr->iType %ld, emr->nSize %lu\n", emr->iType, emr->nSize);
+ /*trace("emr->iType 0x%04lx, emr->nSize 0x%04lx\n", emr->iType, emr->nSize);*/
+ offset += emr->nSize;
+ }
+}
+
+/* Compare the EMF produced by a test function with the
+ * expected raw EMF data in "bits".
+ * Return value is 0 for a perfect match,
+ * -1 if lengths aren't equal,
+ * otherwise returns the number of non-matching bytes.
+ */
+static int compare_emf_bits(const HENHMETAFILE mf, const unsigned char *bits,
+ UINT bsize, const char *desc, BOOL todo)
+{
+ unsigned char buf[MF_BUFSIZE];
+ UINT mfsize, i;
+ int diff;
+
+ mfsize = GetEnhMetaFileBits(mf, MF_BUFSIZE, buf);
+ ok (mfsize > 0, "%s: GetEnhMetaFileBits failed\n", desc);
+
+ if (mfsize < MF_BUFSIZE)
+ ok(mfsize == bsize, "%s: mfsize=%d, bsize=%d\n", desc, mfsize, bsize);
+ else
+ ok(bsize >= MF_BUFSIZE, "%s: mfsize > bufsize (%d bytes), bsize=%d\n",
+ desc, mfsize, bsize);
+ if (mfsize != bsize)
+ return -1;
+
+ diff = 0;
+ for (i = 0; i < bsize; i++)
+ {
+ if (buf[i] != bits[i])
+ diff++;
+ }
+ if (diff != 0 && todo)
+ {
+ todo_wine
+ {
+ ok(diff == 0, "%s: mfsize=%d, bsize=%d, diff=%d\n",
+ desc, mfsize, bsize, diff);
+ }
+ return 0;
+ }
+ else
+ {
+ ok(diff == 0, "%s: mfsize=%d, bsize=%d, diff=%d\n",
+ desc, mfsize, bsize, diff);
+
+ return diff;
+ }
+}
+
/* Test a blank metafile. May be used as a template for new tests. */
static void test_mf_Blank(void)
@@ -548,7 +700,10 @@ static void test_mf_Blank(void)
if (compare_mf_bits (hMetafile, MF_BLANK_BITS, sizeof(MF_BLANK_BITS),
"mf_blank") != 0)
- dump_mf_bits (hMetafile, "mf_Blank");
+ {
+ dump_mf_bits(hMetafile, "mf_Blank");
+ EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
+ }
ret = DeleteMetaFile(hMetafile);
ok( ret, "DeleteMetaFile(%p) error %ld\n", hMetafile, GetLastError());
@@ -574,7 +729,10 @@ static void test_CopyMetaFile(void)
if (compare_mf_bits (hMetafile, MF_BLANK_BITS, sizeof(MF_BLANK_BITS),
"mf_blank") != 0)
- dump_mf_bits (hMetafile, "mf_Blank");
+ {
+ dump_mf_bits(hMetafile, "mf_Blank");
+ EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
+ }
GetTempPathA(MAX_PATH, temp_path);
GetTempFileNameA(temp_path, "wmf", 0, mf_name);
@@ -589,7 +747,10 @@ static void test_CopyMetaFile(void)
ok( ret, "DeleteMetaFile(%p) error %ld\n", hMetafile, GetLastError());
if (compare_mf_disk_bits(mf_name, MF_BLANK_BITS, sizeof(MF_BLANK_BITS), "mf_blank") != 0)
- dump_mf_bits(hmf_copy, "mf_Blank");
+ {
+ dump_mf_bits(hMetafile, "mf_Blank");
+ EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
+ }
ret = DeleteMetaFile(hmf_copy);
ok( ret, "DeleteMetaFile(%p) error %ld\n", hmf_copy, GetLastError());
@@ -611,7 +772,10 @@ static void test_SetMetaFileBits(void)
ok(type == OBJ_METAFILE, "SetMetaFileBitsEx created object with type %d\n", type);
if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
+ {
dump_mf_bits(hmf, "mf_Graphics");
+ EnumMetaFile(0, hmf, mf_enum_proc, 0);
+ }
ret = DeleteMetaFile(hmf);
ok(ret, "DeleteMetaFile(%p) error %ld\n", hmf, GetLastError());
@@ -653,7 +817,10 @@ static void test_SetMetaFileBits(void)
ok(hmf != 0, "SetMetaFileBitsEx error %ld\n", GetLastError());
if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
+ {
dump_mf_bits(hmf, "mf_Graphics");
+ EnumMetaFile(0, hmf, mf_enum_proc, 0);
+ }
ret = DeleteMetaFile(hmf);
ok(ret, "DeleteMetaFile(%p) error %ld\n", hmf, GetLastError());
@@ -667,7 +834,10 @@ static void test_SetMetaFileBits(void)
ok(hmf != 0, "SetMetaFileBitsEx error %ld\n", GetLastError());
if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
+ {
dump_mf_bits(hmf, "mf_Graphics");
+ EnumMetaFile(0, hmf, mf_enum_proc, 0);
+ }
ret = DeleteMetaFile(hmf);
ok(ret, "DeleteMetaFile(%p) error %ld\n", hmf, GetLastError());
@@ -711,7 +881,10 @@ static void test_mf_Graphics(void)
if (compare_mf_bits (hMetafile, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS),
"mf_Graphics") != 0)
- dump_mf_bits (hMetafile, "mf_Graphics");
+ {
+ dump_mf_bits(hMetafile, "mf_Graphics");
+ EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
+ }
ret = DeleteMetaFile(hMetafile);
ok( ret, "DeleteMetaFile(%p) error %ld\n",
@@ -749,7 +922,10 @@ static void test_mf_PatternBrush(void)
if (compare_mf_bits (hMetafile, MF_PATTERN_BRUSH_BITS, sizeof(MF_PATTERN_BRUSH_BITS),
"mf_Pattern_Brush") != 0)
- dump_mf_bits (hMetafile, "mf_Pattern_Brush");
+ {
+ dump_mf_bits(hMetafile, "mf_Pattern_Brush");
+ EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
+ }
ret = DeleteMetaFile(hMetafile);
ok( ret, "DeleteMetaFile error %ld\n", GetLastError());
@@ -761,6 +937,88 @@ static void test_mf_PatternBrush(void)
HeapFree (GetProcessHeap(), 0, orig_lb);
}
+static void test_mf_ExtTextOut_on_path(void)
+{
+ HDC hdcMetafile;
+ HMETAFILE hMetafile;
+ BOOL ret;
+ static const INT dx[4] = { 3, 5, 8, 12 };
+
+ hdcMetafile = CreateMetaFileA(NULL);
+ ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %ld\n", GetLastError());
+ trace("hdcMetafile %p\n", hdcMetafile);
+
+ ret = BeginPath(hdcMetafile);
+ ok(!ret, "BeginPath on metafile DC should fail\n");
+
+ ret = ExtTextOutA(hdcMetafile, 11, 22, 0, NULL, "Test", 4, dx);
+ ok(ret, "ExtTextOut error %ld\n", GetLastError());
+
+ ret = EndPath(hdcMetafile);
+ ok(!ret, "EndPath on metafile DC should fail\n");
+
+ hMetafile = CloseMetaFile(hdcMetafile);
+ ok(hMetafile != 0, "CloseMetaFile error %ld\n", GetLastError());
+
+ if (compare_mf_bits(hMetafile, MF_TEXTOUT_ON_PATH_BITS, sizeof(MF_TEXTOUT_ON_PATH_BITS),
+ "mf_TextOut_on_path") != 0)
+ {
+ dump_mf_bits(hMetafile, "mf_TextOut_on_path");
+ EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
+ }
+
+ ret = DeleteMetaFile(hMetafile);
+ ok(ret, "DeleteMetaFile(%p) error %ld\n", hMetafile, GetLastError());
+}
+
+static void test_emf_ExtTextOut_on_path(void)
+{
+ HWND hwnd;
+ HDC hdcDisplay, hdcMetafile;
+ HENHMETAFILE hMetafile;
+ BOOL ret;
+ static const INT dx[4] = { 3, 5, 8, 12 };
+
+ /* Win9x doesn't play EMFs on invisible windows */
+ hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
+ 0, 0, 200, 200, 0, 0, 0, NULL);
+ ok(hwnd != 0, "CreateWindowExA error %ld\n", GetLastError());
+
+ hdcDisplay = GetDC(hwnd);
+ ok(hdcDisplay != 0, "GetDC error %ld\n", GetLastError());
+
+ hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL);
+ ok(hdcMetafile != 0, "CreateEnhMetaFileA error %ld\n", GetLastError());
+
+ ret = BeginPath(hdcMetafile);
+ ok(ret, "BeginPath error %ld\n", GetLastError());
+
+ ret = ExtTextOutA(hdcMetafile, 11, 22, 0, NULL, "Test", 4, dx);
+ ok(ret, "ExtTextOut error %ld\n", GetLastError());
+
+ ret = EndPath(hdcMetafile);
+ ok(ret, "EndPath error %ld\n", GetLastError());
+
+ hMetafile = CloseEnhMetaFile(hdcMetafile);
+ ok(hMetafile != 0, "CloseEnhMetaFile error %ld\n", GetLastError());
+
+ /* this doesn't succeed yet: EMF has correct size, all EMF records
+ * are there, but their contents don't match for different reasons.
+ */
+ if (compare_emf_bits(hMetafile, EMF_TEXTOUT_ON_PATH_BITS, sizeof(EMF_TEXTOUT_ON_PATH_BITS),
+ "emf_TextOut_on_path", TRUE) != 0)
+ {
+ dump_emf_bits(hMetafile, "emf_TextOut_on_path");
+ dump_emf_records(hMetafile, "emf_TextOut_on_path");
+ }
+
+ ret = DeleteEnhMetaFile(hMetafile);
+ ok(ret, "DeleteEnhMetaFile error %ld\n", GetLastError());
+ ret = ReleaseDC(hwnd, hdcDisplay);
+ ok(ret, "ReleaseDC error %ld\n", GetLastError());
+ DestroyWindow(hwnd);
+}
+
static INT CALLBACK EmfEnumProc(HDC hdc, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR, INT nObj, LPARAM lpData)
{
LPMETAFILEPICT lpMFP = (LPMETAFILEPICT)lpData;
@@ -927,6 +1185,8 @@ START_TEST(metafile)
test_mf_PatternBrush();
test_CopyMetaFile();
test_SetMetaFileBits();
+ test_mf_ExtTextOut_on_path();
+ test_emf_ExtTextOut_on_path();
/* For metafile conversions */
test_mf_conversions();
More information about the wine-patches
mailing list