First draft of ExtTextOut on an open path.
This commit is contained in:
parent
de8f8334f0
commit
e41ddd052a
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
204
dlls/gdi/path.c
204
dlls/gdi/path.c
|
@ -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.
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Reference in New Issue