First draft of ExtTextOut on an open path.

This commit is contained in:
Dmitry Timoshkov 2005-11-07 16:40:20 +00:00 committed by Alexandre Julliard
parent de8f8334f0
commit e41ddd052a
5 changed files with 495 additions and 19 deletions

View File

@ -722,7 +722,8 @@ BOOL EMFDRV_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
nSize = sizeof(*pemr) + ((count+1) & ~1) * sizeof(WCHAR) + count * sizeof(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 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nSize);
pemr->emr.iType = EMR_EXTTEXTOUTW; pemr->emr.iType = EMR_EXTTEXTOUTW;

View File

@ -1759,14 +1759,7 @@ BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
if (flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN | ETO_PDY)) if (flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN | ETO_PDY))
FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN | ETO_PDY unimplemented\n"); FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN | ETO_PDY unimplemented\n");
if(PATH_IsPathOpen(dc->path)) if (!dc->funcs->pExtTextOut && !PATH_IsPathOpen(dc->path))
{
FIXME("called on an open path\n");
GDI_ReleaseObj( hdc );
return ret;
}
if(!dc->funcs->pExtTextOut)
{ {
GDI_ReleaseObj( hdc ); GDI_ReleaseObj( hdc );
return ret; return ret;
@ -1854,7 +1847,7 @@ BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
if(rc.top > rc.bottom) {INT tmp = rc.top; rc.top = rc.bottom; rc.bottom = tmp;} 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); dc->funcs->pExtTextOut(dc->physDev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
if(count == 0) if(count == 0)
@ -1961,7 +1954,7 @@ BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
break; break;
} }
if(GetBkMode(hdc) != TRANSPARENT) if (GetBkMode(hdc) != TRANSPARENT && !PATH_IsPathOpen(dc->path))
{ {
if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE))) if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
{ {
@ -2012,7 +2005,12 @@ BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
} }
if(span) 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, (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
glyphs, span, deltas ? deltas + i - span : NULL); glyphs, span, deltas ? deltas + i - span : NULL);
span = 0; span = 0;
@ -2023,7 +2021,13 @@ BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
if(i == count - 1) 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), y - (offsets ? offsets[count - span] * sinEsc : 0),
(flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc, (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
glyphs, span, deltas ? deltas + count - span : NULL); glyphs, span, deltas ? deltas + count - span : NULL);
@ -2040,7 +2044,12 @@ BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
GetGlyphIndicesW(hdc, reordered_str, count, glyphs, 0); GetGlyphIndicesW(hdc, reordered_str, count, glyphs, 0);
flags |= ETO_GLYPH_INDEX; 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); glyphs ? glyphs : reordered_str, count, deltas);
} }

View File

@ -405,6 +405,8 @@ extern BOOL PATH_AssignGdiPath(GdiPath *pPathDest, const GdiPath *pPathSrc);
extern BOOL PATH_MoveTo(DC *dc); extern BOOL PATH_MoveTo(DC *dc);
extern BOOL PATH_LineTo(DC *dc, INT x, INT y); 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_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_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, extern BOOL PATH_Arc(DC *dc, INT x1, INT y1, INT x2, INT y2,
INT xStart, INT yStart, INT xEnd, INT yEnd, INT lines); INT xStart, INT yStart, INT xEnd, INT yEnd, INT lines);

View File

@ -3,6 +3,7 @@
* *
* Copyright 1997, 1998 Martin Boehme * Copyright 1997, 1998 Martin Boehme
* 1999 Huw D M Davies * 1999 Huw D M Davies
* Copyright 2005 Dmitry Timoshkov
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -26,6 +27,7 @@
#include <math.h> #include <math.h>
#include <stdarg.h> #include <stdarg.h>
#include <string.h> #include <string.h>
#include <stdlib.h>
#if defined(HAVE_FLOAT_H) #if defined(HAVE_FLOAT_H)
#include <float.h> #include <float.h>
#endif #endif
@ -1212,6 +1214,208 @@ static BOOL PATH_PathToRegion(GdiPath *pPath, INT nPolyFillMode,
return TRUE; 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 /* PATH_EmptyPath
* *
* Removes all entries from the path and sets the path state to PATH_Null. * Removes all entries from the path and sets the path state to PATH_Null.

View File

@ -422,6 +422,63 @@ static const unsigned char MF_PATTERN_BRUSH_BITS[] = {
0x00, 0x00 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 /* For debugging or dumping the raw metafiles produced by
* new test functions. * new test functions.
*/ */
@ -521,6 +578,101 @@ static int compare_mf_disk_bits(LPCSTR name, const BYTE *bits, UINT bsize, const
return diff; 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. */ /* Test a blank metafile. May be used as a template for new tests. */
static void test_mf_Blank(void) 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), if (compare_mf_bits (hMetafile, MF_BLANK_BITS, sizeof(MF_BLANK_BITS),
"mf_blank") != 0) "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); ret = DeleteMetaFile(hMetafile);
ok( ret, "DeleteMetaFile(%p) error %ld\n", hMetafile, GetLastError()); 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), if (compare_mf_bits (hMetafile, MF_BLANK_BITS, sizeof(MF_BLANK_BITS),
"mf_blank") != 0) "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); GetTempPathA(MAX_PATH, temp_path);
GetTempFileNameA(temp_path, "wmf", 0, mf_name); 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()); 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) 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); ret = DeleteMetaFile(hmf_copy);
ok( ret, "DeleteMetaFile(%p) error %ld\n", hmf_copy, GetLastError()); 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); 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) if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
{
dump_mf_bits(hmf, "mf_Graphics"); dump_mf_bits(hmf, "mf_Graphics");
EnumMetaFile(0, hmf, mf_enum_proc, 0);
}
ret = DeleteMetaFile(hmf); ret = DeleteMetaFile(hmf);
ok(ret, "DeleteMetaFile(%p) error %ld\n", hmf, GetLastError()); 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()); ok(hmf != 0, "SetMetaFileBitsEx error %ld\n", GetLastError());
if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0) if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
{
dump_mf_bits(hmf, "mf_Graphics"); dump_mf_bits(hmf, "mf_Graphics");
EnumMetaFile(0, hmf, mf_enum_proc, 0);
}
ret = DeleteMetaFile(hmf); ret = DeleteMetaFile(hmf);
ok(ret, "DeleteMetaFile(%p) error %ld\n", hmf, GetLastError()); 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()); ok(hmf != 0, "SetMetaFileBitsEx error %ld\n", GetLastError());
if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0) if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
{
dump_mf_bits(hmf, "mf_Graphics"); dump_mf_bits(hmf, "mf_Graphics");
EnumMetaFile(0, hmf, mf_enum_proc, 0);
}
ret = DeleteMetaFile(hmf); ret = DeleteMetaFile(hmf);
ok(ret, "DeleteMetaFile(%p) error %ld\n", hmf, GetLastError()); 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), if (compare_mf_bits (hMetafile, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS),
"mf_Graphics") != 0) "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); ret = DeleteMetaFile(hMetafile);
ok( ret, "DeleteMetaFile(%p) error %ld\n", 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), if (compare_mf_bits (hMetafile, MF_PATTERN_BRUSH_BITS, sizeof(MF_PATTERN_BRUSH_BITS),
"mf_Pattern_Brush") != 0) "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); ret = DeleteMetaFile(hMetafile);
ok( ret, "DeleteMetaFile error %ld\n", GetLastError()); ok( ret, "DeleteMetaFile error %ld\n", GetLastError());
@ -761,6 +937,88 @@ static void test_mf_PatternBrush(void)
HeapFree (GetProcessHeap(), 0, orig_lb); 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) static INT CALLBACK EmfEnumProc(HDC hdc, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR, INT nObj, LPARAM lpData)
{ {
LPMETAFILEPICT lpMFP = (LPMETAFILEPICT)lpData; LPMETAFILEPICT lpMFP = (LPMETAFILEPICT)lpData;
@ -927,6 +1185,8 @@ START_TEST(metafile)
test_mf_PatternBrush(); test_mf_PatternBrush();
test_CopyMetaFile(); test_CopyMetaFile();
test_SetMetaFileBits(); test_SetMetaFileBits();
test_mf_ExtTextOut_on_path();
test_emf_ExtTextOut_on_path();
/* For metafile conversions */ /* For metafile conversions */
test_mf_conversions(); test_mf_conversions();