Authors: Mike McCormack <mike@codeweavers.com>, Huw Davies <huw@codeweavers.com>

- make world transforms work in EMFs
- fix declaration of GDICOMMENT_* macros
- refuse to load unaligned EMFs
- fix SetWinMetaFileBits
oldstable
Alexandre Julliard 2003-02-14 23:30:27 +00:00
parent 51e4839fb0
commit 80774de724
2 changed files with 474 additions and 106 deletions

View File

@ -2518,8 +2518,8 @@ typedef struct {
INT nBreakCount;
} EMRSETTEXTJUSTIFICATION, *PEMRSETTEXTJUSTIFICATION;
typedef INT (CALLBACK *ENHMFENUMPROC)(HDC, LPHANDLETABLE,
LPENHMETARECORD, INT, LPVOID);
typedef INT (CALLBACK *ENHMFENUMPROC)(HDC, HANDLETABLE *,
const ENHMETARECORD *, INT, LPARAM);
#define EMR_HEADER 1
#define EMR_POLYBEZIER 2
@ -2649,11 +2649,13 @@ typedef INT (CALLBACK *ENHMFENUMPROC)(HDC, LPHANDLETABLE,
#define ENHMETA_SIGNATURE 1179469088
#define ENHMETA_STOCK_OBJECT 0x80000000
#define GDICPMMENT_INDENTIFIER 0x43494447
#define GDICOMMENT_WINDOWS_METAFILE 0x80000000
#define GDICOMMENT_BEGINGROUP 0x80000001
#define GDICOMMENT_ENDGROUP 0x80000002
#define GDICOMMENT_MULTIFORMATS 0x80000003
#define GDICOMMENT_IDENTIFIER 0x43494447
#define GDICOMMENT_WINDOWS_METAFILE 0x80000001
#define GDICOMMENT_BEGINGROUP 0x00000002
#define GDICOMMENT_ENDGROUP 0x00000003
#define GDICOMMENT_MULTIFORMATS 0x40000004
#define GDICOMMENT_UNICODE_STRING 0x00000040
#define GDICOMMENT_UNICODE_END 0x00000080
#define EPS_SIGNATURE 0x46535045
#define CCHDEVICENAME 32

View File

@ -123,10 +123,21 @@ static HENHMETAFILE EMF_GetEnhMetaFile( HANDLE hFile )
if (emh->iType != EMR_HEADER || emh->dSignature != ENHMETA_SIGNATURE) {
WARN("Invalid emf header type 0x%08lx sig 0x%08lx.\n",
emh->iType, emh->dSignature);
UnmapViewOfFile( emh );
return 0;
goto err;
}
/* refuse to load unaligned EMF as Windows does */
if (emh->nBytes & 3)
{
WARN("Refusing to load unaligned EMF\n");
goto err;
}
return EMF_Create_HENHMETAFILE( emh, TRUE );
err:
UnmapViewOfFile( emh );
return 0;
}
@ -284,6 +295,173 @@ UINT WINAPI GetEnhMetaFileBits(
return size;
}
typedef struct enum_emh_data
{
INT mode;
XFORM init_transform;
XFORM world_transform;
INT wndOrgX;
INT wndOrgY;
INT wndExtX;
INT wndExtY;
INT vportOrgX;
INT vportOrgY;
INT vportExtX;
INT vportExtY;
} enum_emh_data;
#define ENUM_GET_PRIVATE_DATA(ht) \
((enum_emh_data*)(((unsigned char*)(ht))-sizeof (enum_emh_data)))
#define WIDTH(rect) ( (rect).right - (rect).left )
#define HEIGHT(rect) ( (rect).bottom - (rect).top )
#define IS_WIN9X() (GetVersion()&0x80000000)
void EMF_Update_MF_Xform(HDC hdc, enum_emh_data *info)
{
XFORM mapping_mode_trans, final_trans;
FLOAT scaleX, scaleY;
scaleX = (FLOAT)info->vportExtX / (FLOAT)info->wndExtX;
scaleY = (FLOAT)info->vportExtY / (FLOAT)info->wndExtY;
mapping_mode_trans.eM11 = scaleX;
mapping_mode_trans.eM12 = 0.0;
mapping_mode_trans.eM21 = 0.0;
mapping_mode_trans.eM22 = scaleY;
mapping_mode_trans.eDx = (FLOAT)info->vportOrgX - scaleX * (FLOAT)info->wndOrgX;
mapping_mode_trans.eDy = (FLOAT)info->vportOrgY - scaleY * (FLOAT)info->wndOrgY;
CombineTransform(&final_trans, &info->world_transform, &mapping_mode_trans);
CombineTransform(&final_trans, &final_trans, &info->init_transform);
if (!SetWorldTransform(hdc, &final_trans))
{
ERR("World transform failed!\n");
}
}
void EMF_SetMapMode(HDC hdc, enum_emh_data *info)
{
INT horzSize = GetDeviceCaps( hdc, HORZSIZE );
INT vertSize = GetDeviceCaps( hdc, VERTSIZE );
INT horzRes = GetDeviceCaps( hdc, HORZRES );
INT vertRes = GetDeviceCaps( hdc, VERTRES );
TRACE("%d\n",info->mode);
switch(info->mode)
{
case MM_TEXT:
info->wndExtX = 1;
info->wndExtY = 1;
info->vportExtX = 1;
info->vportExtY = 1;
break;
case MM_LOMETRIC:
case MM_ISOTROPIC:
info->wndExtX = horzSize;
info->wndExtY = vertSize;
info->vportExtX = horzRes / 10;
info->vportExtY = vertRes / -10;
break;
case MM_HIMETRIC:
info->wndExtX = horzSize * 10;
info->wndExtY = vertSize * 10;
info->vportExtX = horzRes / 10;
info->vportExtY = vertRes / -10;
break;
case MM_LOENGLISH:
info->wndExtX = horzSize;
info->wndExtY = vertSize;
info->vportExtX = 254L * horzRes / 1000;
info->vportExtY = -254L * vertRes / 1000;
break;
case MM_HIENGLISH:
info->wndExtX = horzSize * 10;
info->wndExtY = vertSize * 10;
info->vportExtX = 254L * horzRes / 1000;
info->vportExtY = -254L * vertRes / 1000;
break;
case MM_TWIPS:
info->wndExtX = 144L * horzSize / 10;
info->wndExtY = 144L * vertSize / 10;
info->vportExtX = 254L * horzRes / 1000;
info->vportExtY = -254L * vertRes / 1000;
break;
case MM_ANISOTROPIC:
break;
default:
return;
}
}
/*****************************************************************************
* emr_produces_output
*
* Returns TRUE if the record type writes something to the dc. Used by
* PlayEnhMetaFileRecord to determine whether it needs to update the
* dc's xform when in win9x mode.
*
* FIXME: need to test which records should be here.
*/
static BOOL emr_produces_output(int type)
{
switch(type) {
case EMR_POLYBEZIER:
case EMR_POLYGON:
case EMR_POLYLINE:
case EMR_POLYBEZIERTO:
case EMR_POLYLINETO:
case EMR_POLYPOLYLINE:
case EMR_POLYPOLYGON:
case EMR_SETPIXELV:
case EMR_MOVETOEX:
case EMR_EXCLUDECLIPRECT:
case EMR_INTERSECTCLIPRECT:
case EMR_SELECTOBJECT:
case EMR_ANGLEARC:
case EMR_ELLIPSE:
case EMR_RECTANGLE:
case EMR_ROUNDRECT:
case EMR_ARC:
case EMR_CHORD:
case EMR_PIE:
case EMR_EXTFLOODFILL:
case EMR_LINETO:
case EMR_ARCTO:
case EMR_POLYDRAW:
case EMR_FILLRGN:
case EMR_FRAMERGN:
case EMR_INVERTRGN:
case EMR_PAINTRGN:
case EMR_BITBLT:
case EMR_STRETCHBLT:
case EMR_MASKBLT:
case EMR_PLGBLT:
case EMR_SETDIBITSTODEVICE:
case EMR_STRETCHDIBITS:
case EMR_EXTTEXTOUTA:
case EMR_EXTTEXTOUTW:
case EMR_POLYBEZIER16:
case EMR_POLYGON16:
case EMR_POLYLINE16:
case EMR_POLYBEZIERTO16:
case EMR_POLYLINETO16:
case EMR_POLYPOLYLINE16:
case EMR_POLYPOLYGON16:
case EMR_POLYDRAW16:
case EMR_POLYTEXTOUTA:
case EMR_POLYTEXTOUTW:
case EMR_SMALLTEXTOUT:
case EMR_TRANSPARENTBLT:
return TRUE;
default:
return FALSE;
}
}
/*****************************************************************************
* PlayEnhMetaFileRecord (GDI32.@)
*
@ -294,6 +472,10 @@ UINT WINAPI GetEnhMetaFileBits(
* BUGS
* Many unimplemented records.
* No error handling on record play failures (ie checking return codes)
*
* NOTES
* WinNT actually updates the current world transform in this function
* whereas Win9x does not.
*/
BOOL WINAPI PlayEnhMetaFileRecord(
HDC hdc, /* [in] device context in which to render EMF record */
@ -303,7 +485,8 @@ BOOL WINAPI PlayEnhMetaFileRecord(
)
{
int type;
POINT pt[2];
RECT tmprc;
enum_emh_data *info = ENUM_GET_PRIVATE_DATA(handletable);
TRACE("hdc = %p, handletable = %p, record = %p, numHandles = %d\n",
hdc, handletable, mr, handles);
@ -311,6 +494,10 @@ BOOL WINAPI PlayEnhMetaFileRecord(
type = mr->iType;
/* In Win9x mode we update the xform if the record will produce output */
if ( IS_WIN9X() && emr_produces_output(type) )
EMF_Update_MF_Xform(hdc, info);
TRACE(" type=%d\n", type);
switch(type)
{
@ -328,7 +515,11 @@ BOOL WINAPI PlayEnhMetaFileRecord(
case EMR_SETMAPMODE:
{
PEMRSETMAPMODE pSetMapMode = (PEMRSETMAPMODE) mr;
SetMapMode(hdc, pSetMapMode->iMode);
if(info->mode == pSetMapMode->iMode)
break;
info->mode = pSetMapMode->iMode;
EMF_SetMapMode(hdc, info);
break;
}
case EMR_SETBKMODE:
@ -418,38 +609,46 @@ BOOL WINAPI PlayEnhMetaFileRecord(
}
case EMR_SETWINDOWORGEX:
{
XFORM xform;
PEMRSETWINDOWORGEX pSetWindowOrgEx = (PEMRSETWINDOWORGEX) mr;
PEMRSETWINDOWORGEX pSetWindowOrgEx = (PEMRSETWINDOWORGEX) mr;
xform.eM11 = 1;
xform.eM12 = 0;
xform.eM21 = 0;
xform.eM22 = 1;
xform.eDx = -pSetWindowOrgEx->ptlOrigin.x;
xform.eDy = -pSetWindowOrgEx->ptlOrigin.y;
info->wndOrgX = pSetWindowOrgEx->ptlOrigin.x;
info->wndOrgY = pSetWindowOrgEx->ptlOrigin.y;
ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY);
break;
TRACE("SetWindowOrgEx: %d,%d\n",info->wndOrgX,info->wndOrgY);
break;
}
case EMR_SETWINDOWEXTEX:
{
PEMRSETWINDOWEXTEX pSetWindowExtEx = (PEMRSETWINDOWEXTEX) mr;
SetWindowExtEx(hdc, pSetWindowExtEx->szlExtent.cx,
pSetWindowExtEx->szlExtent.cy, NULL);
if(info->mode != MM_ISOTROPIC && info->mode != MM_ANISOTROPIC)
break;
info->wndExtX = pSetWindowExtEx->szlExtent.cx;
info->wndExtY = pSetWindowExtEx->szlExtent.cy;
TRACE("SetWindowExtEx: %d,%d\n",info->wndExtX,info->wndExtY);
break;
}
case EMR_SETVIEWPORTORGEX:
{
PEMRSETVIEWPORTORGEX pSetViewportOrgEx = (PEMRSETVIEWPORTORGEX) mr;
SetViewportOrgEx(hdc, pSetViewportOrgEx->ptlOrigin.x,
pSetViewportOrgEx->ptlOrigin.y, NULL);
enum_emh_data *info = ENUM_GET_PRIVATE_DATA(handletable);
info->vportOrgX = pSetViewportOrgEx->ptlOrigin.x;
info->vportOrgY = pSetViewportOrgEx->ptlOrigin.y;
TRACE("SetViewportOrgEx: %d,%d\n",info->vportOrgX,info->vportOrgY);
break;
}
case EMR_SETVIEWPORTEXTEX:
{
PEMRSETVIEWPORTEXTEX pSetViewportExtEx = (PEMRSETVIEWPORTEXTEX) mr;
SetViewportExtEx(hdc, pSetViewportExtEx->szlExtent.cx,
pSetViewportExtEx->szlExtent.cy, NULL);
enum_emh_data *info = ENUM_GET_PRIVATE_DATA(handletable);
if(info->mode != MM_ISOTROPIC && info->mode != MM_ANISOTROPIC)
break;
info->vportExtX = pSetViewportExtEx->szlExtent.cx;
info->vportExtY = pSetViewportExtEx->szlExtent.cy;
TRACE("SetViewportExtEx: %d,%d\n",info->vportExtX,info->vportExtY);
break;
}
case EMR_CREATEPEN:
@ -698,11 +897,14 @@ BOOL WINAPI PlayEnhMetaFileRecord(
case EMR_EXTSELECTCLIPRGN:
{
#if 0
PEMREXTSELECTCLIPRGN lpRgn = (PEMREXTSELECTCLIPRGN)mr;
HRGN hRgn = ExtCreateRegion(NULL, lpRgn->cbRgnData, (RGNDATA *)lpRgn->RgnData);
ExtSelectClipRgn(hdc, hRgn, (INT)(lpRgn->iMode));
/* ExtSelectClipRgn created a copy of the region */
DeleteObject(hRgn);
#endif
FIXME("ExtSelectClipRgn\n");
break;
}
@ -715,7 +917,7 @@ BOOL WINAPI PlayEnhMetaFileRecord(
case EMR_SETWORLDTRANSFORM:
{
PEMRSETWORLDTRANSFORM lpXfrm = (PEMRSETWORLDTRANSFORM)mr;
SetWorldTransform( hdc, &lpXfrm->xform );
info->world_transform = lpXfrm->xform;
break;
}
@ -830,6 +1032,7 @@ BOOL WINAPI PlayEnhMetaFileRecord(
OffsetClipRgn( hdc,
(INT)lpOffsetClipRgn->ptlOffset.x,
(INT)lpOffsetClipRgn->ptlOffset.y );
FIXME("OffsetClipRgn\n");
break;
}
@ -843,6 +1046,7 @@ BOOL WINAPI PlayEnhMetaFileRecord(
lpExcludeClipRect->rclClip.top,
lpExcludeClipRect->rclClip.right,
lpExcludeClipRect->rclClip.bottom );
FIXME("ExcludeClipRect\n");
break;
}
@ -851,12 +1055,24 @@ BOOL WINAPI PlayEnhMetaFileRecord(
{
PEMRSCALEVIEWPORTEXTEX lpScaleViewportExtEx = (PEMRSCALEVIEWPORTEXTEX)mr;
ScaleViewportExtEx( hdc,
lpScaleViewportExtEx->xNum,
lpScaleViewportExtEx->xDenom,
lpScaleViewportExtEx->yNum,
lpScaleViewportExtEx->yDenom,
NULL );
if ((info->mode != MM_ISOTROPIC) && (info->mode != MM_ANISOTROPIC))
break;
if (!lpScaleViewportExtEx->xNum || !lpScaleViewportExtEx->xDenom ||
!lpScaleViewportExtEx->xNum || !lpScaleViewportExtEx->yDenom)
break;
info->vportExtX = (info->vportExtX * lpScaleViewportExtEx->xNum) /
lpScaleViewportExtEx->xDenom;
info->vportExtY = (info->vportExtY * lpScaleViewportExtEx->yNum) /
lpScaleViewportExtEx->yDenom;
if (info->vportExtX == 0) info->vportExtX = 1;
if (info->vportExtY == 0) info->vportExtY = 1;
if (info->mode == MM_ISOTROPIC)
FIXME("EMRSCALEVIEWPORTEXTEX MM_ISOTROPIC mapping\n");
/* MAPPING_FixIsotropic( dc ); */
TRACE("EMRSCALEVIEWPORTEXTEX %ld/%ld %ld/%ld\n",
lpScaleViewportExtEx->xNum,lpScaleViewportExtEx->xDenom,
lpScaleViewportExtEx->yNum,lpScaleViewportExtEx->yDenom);
break;
}
@ -865,12 +1081,24 @@ BOOL WINAPI PlayEnhMetaFileRecord(
{
PEMRSCALEWINDOWEXTEX lpScaleWindowExtEx = (PEMRSCALEWINDOWEXTEX)mr;
ScaleWindowExtEx( hdc,
lpScaleWindowExtEx->xNum,
lpScaleWindowExtEx->xDenom,
lpScaleWindowExtEx->yNum,
lpScaleWindowExtEx->yDenom,
NULL );
if ((info->mode != MM_ISOTROPIC) && (info->mode != MM_ANISOTROPIC))
break;
if (!lpScaleWindowExtEx->xNum || !lpScaleWindowExtEx->xDenom ||
!lpScaleWindowExtEx->xNum || !lpScaleWindowExtEx->yDenom)
break;
info->wndExtX = (info->wndExtX * lpScaleWindowExtEx->xNum) /
lpScaleWindowExtEx->xDenom;
info->wndExtY = (info->wndExtY * lpScaleWindowExtEx->yNum) /
lpScaleWindowExtEx->yDenom;
if (info->wndExtX == 0) info->wndExtX = 1;
if (info->wndExtY == 0) info->wndExtY = 1;
if (info->mode == MM_ISOTROPIC)
FIXME("EMRSCALEWINDOWEXTEX MM_ISOTROPIC mapping\n");
/* MAPPING_FixIsotropic( dc ); */
TRACE("EMRSCALEWINDOWEXTEX %ld/%ld %ld/%ld\n",
lpScaleWindowExtEx->xNum,lpScaleWindowExtEx->xDenom,
lpScaleWindowExtEx->yNum,lpScaleWindowExtEx->yDenom);
break;
}
@ -879,9 +1107,24 @@ BOOL WINAPI PlayEnhMetaFileRecord(
{
PEMRMODIFYWORLDTRANSFORM lpModifyWorldTrans = (PEMRMODIFYWORLDTRANSFORM)mr;
ModifyWorldTransform( hdc, &lpModifyWorldTrans->xform,
lpModifyWorldTrans->iMode );
switch(lpModifyWorldTrans->iMode) {
case MWT_IDENTITY:
info->world_transform.eM11 = info->world_transform.eM22 = 1;
info->world_transform.eM12 = info->world_transform.eM21 = 0;
info->world_transform.eDx = info->world_transform.eDy = 0;
break;
case MWT_LEFTMULTIPLY:
CombineTransform(&info->world_transform, &lpModifyWorldTrans->xform,
&info->world_transform);
break;
case MWT_RIGHTMULTIPLY:
CombineTransform(&info->world_transform, &info->world_transform,
&lpModifyWorldTrans->xform);
break;
default:
FIXME("Unknown imode %ld\n", lpModifyWorldTrans->iMode);
break;
}
break;
}
@ -1565,12 +1808,19 @@ BOOL WINAPI PlayEnhMetaFileRecord(
FIXME("type %d is unimplemented\n", type);
break;
}
tmprc.left = tmprc.top = 0;
tmprc.right = tmprc.bottom = 1000;
LPtoDP(hdc, (POINT*)&tmprc, 2);
TRACE("L:0,0 - 1000,1000 -> D:%ld,%ld - %ld,%ld\n", tmprc.left,
tmprc.top, tmprc.right, tmprc.bottom);
if ( !IS_WIN9X() )
{
/* WinNT - update the transform (win9x updates when the next graphics output
record is played). */
EMF_Update_MF_Xform(hdc, info);
}
pt[0].x = pt[0].y = 0;
pt[1].x = pt[1].y = 1000;
LPtoDP(hdc, pt, 2);
TRACE("L:0,0 - 1000,1000 -> D:%ld,%ld - %ld,%ld\n", pt[0].x, pt[0].y,
pt[1].x, pt[1].y);
return TRUE;
}
@ -1591,6 +1841,23 @@ BOOL WINAPI PlayEnhMetaFileRecord(
*
* BUGS
* Ignores rect.
*
* NOTES
* This function behaves differently in Win9x and WinNT.
*
* In WinNT, the DC's world transform is updated as the EMF changes
* the Window/Viewport Extent and Origin or it's world transform.
* The actual Window/Viewport Extent and Origin are left untouched.
*
* In Win9x, the DC is left untouched, and PlayEnhMetaFileRecord
* updates the scaling itself but only just before a record that
* writes anything to the DC.
*
* I'm not sure where the data (enum_emh_data) is stored in either
* version. For this implementation, it is stored before the handle
* table, but it could be stored in the DC, in the EMF handle or in
* TLS.
* MJM 5 Oct 2002
*/
BOOL WINAPI EnumEnhMetaFile(
HDC hdc, /* [in] device context to pass to _EnhMetaFunc_ */
@ -1607,12 +1874,14 @@ BOOL WINAPI EnumEnhMetaFile(
UINT i;
HANDLETABLE *ht;
INT savedMode = 0;
FLOAT xSrcPixSize, ySrcPixSize, xscale, yscale;
XFORM savedXform, xform;
XFORM savedXform;
HPEN hPen = NULL;
HBRUSH hBrush = NULL;
HFONT hFont = NULL;
POINT pt[2];
enum_emh_data *info;
SIZE vp_size, win_size;
POINT vp_org, win_org;
INT mapMode = MM_TEXT;
if(!lpRect)
{
@ -1626,44 +1895,37 @@ BOOL WINAPI EnumEnhMetaFile(
return FALSE;
}
ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof(HANDLETABLE) * emh->nHandles );
if(!ht)
info = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof (enum_emh_data) + sizeof(HANDLETABLE) * emh->nHandles );
if(!info)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
info->wndOrgX = 0;
info->wndOrgY = 0;
info->wndExtX = 1;
info->wndExtY = 1;
info->vportOrgX = 0;
info->vportOrgY = 0;
info->vportExtX = 1;
info->vportExtY = 1;
info->world_transform.eM11 = info->world_transform.eM22 = 1;
info->world_transform.eM12 = info->world_transform.eM21 = 0;
info->world_transform.eDx = info->world_transform.eDy = 0;
ht = (HANDLETABLE*) &info[1];
ht->objectHandle[0] = hmf;
if (hdc && (emh->rclFrame.right - emh->rclFrame.left) && (emh->rclFrame.bottom - emh->rclFrame.top))
if(hdc)
{
TRACE("rect: %ld,%ld - %ld,%ld. rclFrame: %ld,%ld - %ld,%ld\n",
lpRect->left, lpRect->top, lpRect->right, lpRect->bottom,
emh->rclFrame.left, emh->rclFrame.top, emh->rclFrame.right,
emh->rclFrame.bottom);
xSrcPixSize = (FLOAT) emh->szlMillimeters.cx / emh->szlDevice.cx;
ySrcPixSize = (FLOAT) emh->szlMillimeters.cy / emh->szlDevice.cy;
xscale = (FLOAT)(lpRect->right - lpRect->left) * 100.0 /
(emh->rclFrame.right - emh->rclFrame.left) * xSrcPixSize;
yscale = (FLOAT)(lpRect->bottom - lpRect->top) * 100.0 /
(emh->rclFrame.bottom - emh->rclFrame.top) * ySrcPixSize;
xform.eM11 = xscale;
xform.eM12 = 0;
xform.eM21 = 0;
xform.eM22 = yscale;
xform.eDx = (FLOAT) lpRect->left - (lpRect->right - lpRect->left) *
emh->rclFrame.left / (emh->rclFrame.right - emh->rclFrame.left);
xform.eDy = (FLOAT) lpRect->top - (lpRect->bottom - lpRect->top) *
emh->rclFrame.top / (emh->rclFrame.bottom - emh->rclFrame.top);
savedMode = SetGraphicsMode(hdc, GM_ADVANCED);
GetWorldTransform(hdc, &savedXform);
if (!ModifyWorldTransform(hdc, &xform, MWT_RIGHTMULTIPLY)) {
ERR("World transform failed!\n");
}
GetViewportExtEx(hdc, &vp_size);
GetWindowExtEx(hdc, &win_size);
GetViewportOrgEx(hdc, &vp_org);
GetWindowOrgEx(hdc, &win_org);
mapMode = GetMapMode(hdc);
/* save the current pen, brush and font */
hPen = GetCurrentObject(hdc, OBJ_PEN);
@ -1671,13 +1933,69 @@ BOOL WINAPI EnumEnhMetaFile(
hFont = GetCurrentObject(hdc, OBJ_FONT);
}
pt[0].x = pt[0].y = 0;
pt[1].x = pt[1].y = 1000;
LPtoDP(hdc, pt, 2);
TRACE("L:0,0-1000,1000 maps to D:%ld,%ld - %ld,%ld\n", pt[0].x, pt[0].y,
pt[1].x, pt[1].y);
TRACE("nSize = %ld, nBytes = %ld, nHandles = %d, nRecords = %ld, nPalEntries = %ld\n",
emh->nSize, emh->nBytes, emh->nHandles, emh->nRecords, emh->nPalEntries);
info->mode = MM_TEXT;
if ( IS_WIN9X() )
{
/* Win95 leaves the vp/win ext/org info alone */
info->init_transform.eM11 = 1.0;
info->init_transform.eM12 = 0.0;
info->init_transform.eM21 = 0.0;
info->init_transform.eM22 = 1.0;
info->init_transform.eDx = 0.0;
info->init_transform.eDy = 0.0;
}
else
{
/* WinNT combines the vp/win ext/org info into a transform */
FLOAT xscale, yscale;
xscale = (FLOAT)vp_size.cx / (FLOAT)win_size.cx;
yscale = (FLOAT)vp_size.cy / (FLOAT)win_size.cy;
info->init_transform.eM11 = xscale;
info->init_transform.eM12 = 0.0;
info->init_transform.eM21 = 0.0;
info->init_transform.eM22 = yscale;
info->init_transform.eDx = (FLOAT)vp_org.x - xscale * (FLOAT)win_org.x;
info->init_transform.eDy = (FLOAT)vp_org.y - yscale * (FLOAT)win_org.y;
CombineTransform(&info->init_transform, &savedXform, &info->init_transform);
}
if ( WIDTH(emh->rclFrame) && HEIGHT(emh->rclFrame) )
{
FLOAT xSrcPixSize, ySrcPixSize, xscale, yscale;
XFORM xform;
TRACE("rect: %ld,%ld - %ld,%ld. rclFrame: %ld,%ld - %ld,%ld\n",
lpRect->left, lpRect->top, lpRect->right, lpRect->bottom,
emh->rclFrame.left, emh->rclFrame.top, emh->rclFrame.right,
emh->rclFrame.bottom);
xSrcPixSize = (FLOAT) emh->szlMillimeters.cx / emh->szlDevice.cx;
ySrcPixSize = (FLOAT) emh->szlMillimeters.cy / emh->szlDevice.cy;
xscale = (FLOAT) WIDTH(*lpRect) * 100.0 /
WIDTH(emh->rclFrame) * xSrcPixSize;
yscale = (FLOAT) HEIGHT(*lpRect) * 100.0 /
HEIGHT(emh->rclFrame) * ySrcPixSize;
xform.eM11 = xscale;
xform.eM12 = 0;
xform.eM21 = 0;
xform.eM22 = yscale;
xform.eDx = (FLOAT) lpRect->left - (FLOAT) WIDTH(*lpRect) / WIDTH(emh->rclFrame) * emh->rclFrame.left;
xform.eDy = (FLOAT) lpRect->top - (FLOAT) HEIGHT(*lpRect) / HEIGHT(emh->rclFrame) * emh->rclFrame.top;
CombineTransform(&info->init_transform, &xform, &info->init_transform);
}
/* WinNT resets the current vp/win org/ext */
if ( !IS_WIN9X() )
{
SetMapMode(hdc, MM_TEXT);
SetWindowOrgEx(hdc, 0, 0, NULL);
SetViewportOrgEx(hdc, 0, 0, NULL);
EMF_Update_MF_Xform(hdc, info);
}
ret = TRUE;
offset = 0;
@ -1685,7 +2003,7 @@ BOOL WINAPI EnumEnhMetaFile(
{
emr = (ENHMETARECORD *)((char *)emh + offset);
TRACE("Calling EnumFunc with record type %ld, size %ld\n", emr->iType, emr->nSize);
ret = (*callback)(hdc, ht, emr, emh->nHandles, data);
ret = (*callback)(hdc, ht, emr, emh->nHandles, (LPARAM)data);
offset += emr->nSize;
}
@ -1699,19 +2017,24 @@ BOOL WINAPI EnumEnhMetaFile(
SetWorldTransform(hdc, &savedXform);
if (savedMode)
SetGraphicsMode(hdc, savedMode);
SetMapMode(hdc, mapMode);
SetWindowOrgEx(hdc, win_org.x, win_org.y, NULL);
SetWindowExtEx(hdc, win_size.cx, win_size.cy, NULL);
SetViewportOrgEx(hdc, vp_org.x, vp_org.y, NULL);
SetViewportExtEx(hdc, vp_size.cx, vp_size.cy, NULL);
}
for(i = 1; i < emh->nHandles; i++) /* Don't delete element 0 (hmf) */
if( (ht->objectHandle)[i] )
DeleteObject( (ht->objectHandle)[i] );
HeapFree( GetProcessHeap(), 0, ht );
HeapFree( GetProcessHeap(), 0, info );
return ret;
}
static INT CALLBACK EMF_PlayEnhMetaFileCallback(HDC hdc, HANDLETABLE *ht,
ENHMETARECORD *emr,
INT handles, LPVOID data)
const ENHMETARECORD *emr,
INT handles, LPARAM data)
{
return PlayEnhMetaFileRecord(hdc, ht, emr, handles);
}
@ -1798,10 +2121,10 @@ typedef struct tagEMF_PaletteCopy
* NOTE: To be used by GetEnhMetaFilePaletteEntries only!
*/
INT CALLBACK cbEnhPaletteCopy( HDC a,
LPHANDLETABLE b,
LPENHMETARECORD lpEMR,
HANDLETABLE *b,
const ENHMETARECORD *lpEMR,
INT c,
LPVOID lpData )
LPARAM lpData )
{
if ( lpEMR->iType == EMR_EOF )
@ -1854,7 +2177,7 @@ UINT WINAPI GetEnhMetaFilePaletteEntries( HENHMETAFILE hEmf,
infoForCallBack.lpPe = lpPe;
if ( !EnumEnhMetaFile( 0, hEmf, cbEnhPaletteCopy,
&infoForCallBack, NULL ) )
&infoForCallBack, 0 ) )
return GDI_ERROR;
/* Verify that the callback executed correctly */
@ -1868,6 +2191,16 @@ UINT WINAPI GetEnhMetaFilePaletteEntries( HENHMETAFILE hEmf,
return infoForCallBack.cEntries;
}
typedef struct gdi_mf_comment
{
DWORD ident;
DWORD iComment;
DWORD nVersion;
DWORD nChecksum;
DWORD fFlags;
DWORD cbWinMetaFile;
} gdi_mf_comment;
/******************************************************************
* SetWinMetaFileBits (GDI32.@)
*
@ -1883,14 +2216,18 @@ HENHMETAFILE WINAPI SetWinMetaFileBits(UINT cbBuffer,
HMETAFILE hmf = 0;
HENHMETAFILE ret = 0;
HDC hdc = 0, hdcdisp = 0;
INT horzres, vertres;
METAFILEPICT mfp;
RECT rc, *prcFrame = NULL;
gdi_mf_comment *mfcomment;
UINT mfcomment_size;
INT horzres, vertres, horzsize, vertsize, xext, yext;
TRACE("(%d, %p, %p, %p)\n", cbBuffer, lpbBuffer, hdcRef, lpmfp);
if(!(hmf = SetMetaFileBitsEx(cbBuffer, lpbBuffer))) {
WARN("SetMetaFileBitsEx fails\n");
hmf = SetMetaFileBitsEx(cbBuffer, lpbBuffer);
if(!hmf)
{
WARN("SetMetaFileBitsEx failed\n");
return 0;
}
@ -1903,11 +2240,13 @@ HENHMETAFILE WINAPI SetWinMetaFileBits(UINT cbBuffer,
mfp.xExt = 100;
mfp.yExt = 100;
FIXME("Correct Exts from dc\n");
} else
}
else
{
TRACE("mm = %ld %ldx%ld\n", lpmfp->mm, lpmfp->xExt, lpmfp->yExt);
horzres = GetDeviceCaps(hdcRef, HORZRES);
vertres = GetDeviceCaps(hdcRef, VERTRES);
if ( ( mfp.xExt < 0 ) || ( mfp.yExt < 0) )
FIXME("Negative coordinates!\n");
}
if(lpmfp->mm == MM_ISOTROPIC || lpmfp->mm == MM_ANISOTROPIC) {
rc.left = rc.top = 0;
@ -1921,21 +2260,48 @@ HENHMETAFILE WINAPI SetWinMetaFileBits(UINT cbBuffer,
goto end;
}
horzres = GetDeviceCaps(hdcRef, HORZRES);
vertres = GetDeviceCaps(hdcRef, VERTRES);
horzsize = GetDeviceCaps(hdcRef, HORZSIZE);
vertsize = GetDeviceCaps(hdcRef, VERTSIZE);
if(hdcdisp) {
DeleteDC(hdcdisp);
hdcRef = 0;
}
/*
* Write the original METAFILE into the enhanced metafile.
* It is encapsulated in a GDICOMMENT_WINDOWS_METAFILE record.
*/
mfcomment_size = sizeof (gdi_mf_comment) + cbBuffer;
mfcomment = HeapAlloc(GetProcessHeap(), 0, mfcomment_size);
if(mfcomment)
{
mfcomment->ident = GDICOMMENT_IDENTIFIER;
mfcomment->iComment = GDICOMMENT_WINDOWS_METAFILE;
mfcomment->nVersion = 0x00000300;
mfcomment->nChecksum = 0; /* FIXME */
mfcomment->fFlags = 0;
mfcomment->cbWinMetaFile = cbBuffer;
memcpy(&mfcomment[1], lpbBuffer, cbBuffer);
GdiComment(hdc, mfcomment_size, (BYTE*) mfcomment);
HeapFree(GetProcessHeap(), 0, mfcomment);
}
if(lpmfp->mm != MM_TEXT)
SetMapMode(hdc, lpmfp->mm);
SetViewportExtEx(hdc, horzres, vertres, NULL);
SetWindowExtEx(hdc, horzres, vertres, NULL);
/* set the initial viewport:window ratio as 1:1 */
xext = lpmfp->xExt*horzres/(100*horzsize);
yext = lpmfp->yExt*vertres/(100*vertsize);
SetViewportExtEx(hdc, xext, yext, NULL);
SetWindowExtEx(hdc, xext, yext, NULL);
PlayMetaFile(hdc, hmf); /* It's got to be harder than this... */
PlayMetaFile(hdc, hmf);
ret = CloseEnhMetaFile(hdc);
end:
end:
DeleteMetaFile(hmf);
return ret;
}