ChangeLog: 1. Implementation of GetEMFTransform and SetEMFTransform Windows API functions. 2. Fix EnumEnhMetaFile so it renders properly inside the limits of the given rectangle input parameter. Description: 1. GetEMFTransform and SetEMFTransform have been implemented by storing an additional XFORM inside the DC structure to map an EMF to a destination rectangle. 2. Fixing EnumEnhMetaFile relies on the previous GetEMFTransform and SetEMFTransform functions. The EMF mapping transformation is combined to the Wnd2VPort transformation. Warren Baird : Warren_Baird@cimmetry.com Xavier Servettaz diff -ur clean/wine/include/wingdi.h wine/include/wingdi.h --- clean/wine/include/wingdi.h Wed Jan 29 15:31:07 2003 +++ wine/include/wingdi.h Mon Feb 3 18:54:12 2003 @@ -3255,6 +3255,7 @@ COLORREF WINAPI GetDCPenColor(HDC); UINT WINAPI GetDIBColorTable(HDC,UINT,UINT,RGBQUAD*); INT WINAPI GetDIBits(HDC,HBITMAP,UINT,UINT,LPVOID,LPBITMAPINFO,UINT); +BOOL WINAPI GetEMFTransform(HDC, LPXFORM); HENHMETAFILE WINAPI GetEnhMetaFileA(LPCSTR); HENHMETAFILE WINAPI GetEnhMetaFileW(LPCWSTR); #define GetEnhMetaFile WINELIB_NAME_AW(GetEnhMetaFile) @@ -3413,6 +3414,7 @@ INT WINAPI SetDIBits(HDC,HBITMAP,UINT,UINT,LPCVOID,const BITMAPINFO*,UINT); INT WINAPI SetDIBitsToDevice(HDC,INT,INT,DWORD,DWORD,INT, INT,UINT,UINT,LPCVOID,const BITMAPINFO*,UINT); +BOOL WINAPI SetEMFTransform(HDC, const XFORM *); HENHMETAFILE WINAPI SetEnhMetaFileBits(UINT,const BYTE *); INT WINAPI SetGraphicsMode(HDC,INT); INT WINAPI SetICMMode(HDC,INT); diff -ur clean/wine/include/gdi.h wine/include/gdi.h --- clean/wine/include/gdi.h Wed Jan 29 15:31:05 2003 +++ wine/include/gdi.h Mon Feb 3 10:55:03 2003 @@ -159,6 +159,7 @@ XFORM xformWorld2Wnd; /* World-to-window transformation */ XFORM xformWorld2Vport; /* World-to-viewport transformation */ XFORM xformVport2World; /* Inverse of the above transformation */ + XFORM xformEMFmapping; /* Map an EMF to destination rectangle*/ BOOL vport2WorldValid; /* Is xformVport2World valid? */ } DC; diff -ur clean/wine/objects/dc.c wine/objects/dc.c --- clean/wine/objects/dc.c Wed Jan 29 15:31:13 2003 +++ wine/objects/dc.c Mon Feb 3 10:33:17 2003 @@ -119,6 +119,7 @@ dc->xformWorld2Wnd.eDy = 0.0f; dc->xformWorld2Vport = dc->xformWorld2Wnd; dc->xformVport2World = dc->xformWorld2Wnd; + dc->xformEMFmapping = dc->xformWorld2Wnd; dc->vport2WorldValid = TRUE; PATH_InitGdiPath(&dc->path); return dc; @@ -256,9 +257,14 @@ xformWnd2Vport.eDy = (FLOAT)dc->vportOrgY - scaleY * (FLOAT)dc->wndOrgY; + XFORM additionalTransform; /* Combine with the world transformation */ - CombineTransform( &dc->xformWorld2Vport, &dc->xformWorld2Wnd, - &xformWnd2Vport ); + CombineTransform(&additionalTransform, + &dc->xformWorld2Wnd, + &xformWnd2Vport ); + CombineTransform(&dc->xformWorld2Vport, + &additionalTransform, + &dc->xformEMFmapping ); /* Create inverse of world-to-viewport transformation */ dc->vport2WorldValid = DC_InvertXform( &dc->xformWorld2Vport, @@ -314,6 +320,7 @@ newdc->xformWorld2Wnd = dc->xformWorld2Wnd; newdc->xformWorld2Vport = dc->xformWorld2Vport; newdc->xformVport2World = dc->xformVport2World; + newdc->xformEMFmapping = dc->xformEMFmapping; newdc->vport2WorldValid = dc->vport2WorldValid; newdc->wndOrgX = dc->wndOrgX; newdc->wndOrgY = dc->wndOrgY; @@ -402,6 +409,7 @@ dc->xformWorld2Wnd = dcs->xformWorld2Wnd; dc->xformWorld2Vport = dcs->xformWorld2Vport; dc->xformVport2World = dcs->xformVport2World; + dc->xformEMFmapping = dcs->xformEMFmapping; dc->vport2WorldValid = dcs->vport2WorldValid; dc->wndOrgX = dcs->wndOrgX; @@ -976,6 +984,35 @@ return nOldDirection; } +/*********************************************************************** + * GetEMFTransform (GDI32.@) + */ +BOOL WINAPI GetEMFTransform( HDC hdc, LPXFORM xform ) +{ + DC * dc; + if (!xform) return FALSE; + if (!(dc = DC_GetDCPtr( hdc ))) return FALSE; + *xform = dc->xformEMFmapping; + GDI_ReleaseObj( hdc ); + return TRUE; +} + +/*********************************************************************** + * SetEMFTransform (GDI32.@) + */ +BOOL WINAPI SetEMFTransform( HDC hdc, const XFORM *xform ) +{ + BOOL ret = FALSE; + DC *dc = DC_GetDCPtr( hdc ); + if (!dc) { return FALSE;} + if (xform) { + dc->xformEMFmapping = *xform; + DC_UpdateXforms( dc ); + ret = TRUE; + } + GDI_ReleaseObj( hdc ); + return ret; +} /*********************************************************************** * GetWorldTransform (GDI32.@) diff -ur clean/wine/objects/enhmetafile.c wine/objects/enhmetafile.c --- clean/wine/objects/enhmetafile.c Mon Feb 3 19:07:49 2003 +++ wine/objects/enhmetafile.c Mon Feb 3 19:15:45 2003 @@ -418,18 +418,12 @@ } case EMR_SETWINDOWORGEX: { - XFORM xform; - 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; - - ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY); - break; + PEMRSETWINDOWORGEX pSetWindowOrgEx = (PEMRSETWINDOWORGEX) mr; + SetWindowOrgEx(hdc, + pSetWindowOrgEx->ptlOrigin.x, + pSetWindowOrgEx->ptlOrigin.y, + NULL); + break; } case EMR_SETWINDOWEXTEX: { @@ -1608,11 +1602,15 @@ HANDLETABLE *ht; INT savedMode = 0; FLOAT xSrcPixSize, ySrcPixSize, xscale, yscale; - XFORM savedXform, xform; + XFORM savedXform, xform, savedEMFXform; HPEN hPen = NULL; HBRUSH hBrush = NULL; HFONT hFont = NULL; POINT pt[2]; + INT oldvportExtX = 0; + INT oldvportExtY = 0; + INT oldvportOrgX = 0; + INT oldvportOrgY = 0; if(!lpRect) { @@ -1660,10 +1658,59 @@ savedMode = SetGraphicsMode(hdc, GM_ADVANCED); GetWorldTransform(hdc, &savedXform); + GetEMFTransform(hdc, &savedEMFXform); - if (!ModifyWorldTransform(hdc, &xform, MWT_RIGHTMULTIPLY)) { - ERR("World transform failed!\n"); + /* here we combine "out-of-EMF" Wnd2Vport transformation with + the one mapping to the selected output rectangle. + Since they both will be included in the additionalTransform, we ensure + Identity is set to xformWnd2Vport before playing the EMF + + rem: "out-of-EMF" means any transform that is already set for this DC. + */ + + DC *dc = DC_GetDCPtr (hdc); + if (!dc) { + FIXME ("ERROR failed to get DC ptr while playing enhmetafile!/n"); + return FALSE; } + + XFORM xformWnd2Vport; + XFORM additionalTransform; + FLOAT scaleX, scaleY; + + /* Construct a transformation to do the window-to-viewport conversion */ + scaleX = (FLOAT)dc->vportExtX / (FLOAT)dc->wndExtX; + scaleY = (FLOAT)dc->vportExtY / (FLOAT)dc->wndExtY; + xformWnd2Vport.eM11 = scaleX; + xformWnd2Vport.eM12 = 0.0; + xformWnd2Vport.eM21 = 0.0; + xformWnd2Vport.eM22 = scaleY; + xformWnd2Vport.eDx = (FLOAT)dc->vportOrgX - + scaleX * (FLOAT)dc->wndOrgX; + xformWnd2Vport.eDy = (FLOAT)dc->vportOrgY - + scaleY * (FLOAT)dc->wndOrgY; + + /* save old values */ + oldvportExtX = dc->vportExtX; + oldvportExtY = dc->vportExtY; + oldvportOrgX = dc->vportOrgX; + oldvportOrgY = dc->vportOrgY; + + /* set identity */ + dc->vportExtX = dc->wndExtX; + dc->vportExtY = dc->wndExtY; + dc->vportOrgX = dc->wndOrgX; + dc->vportOrgY = dc->wndOrgY; + + /* release DC */ + GDI_ReleaseObj(hdc); + + /* combine transformations */ + CombineTransform(&additionalTransform, + &xform, + &xformWnd2Vport); + + SetEMFTransform(hdc, &additionalTransform); /* save the current pen, brush and font */ hPen = GetCurrentObject(hdc, OBJ_PEN); @@ -1696,7 +1743,22 @@ SelectObject(hdc, hPen); SelectObject(hdc, hFont); + /* reset vport values */ + DC *dc = DC_GetDCPtr (hdc); + if (!dc) { + FIXME ("ERROR failed to get DC ptr while playing enhmetafile!/n"); + return FALSE; + } + dc->vportExtX = oldvportExtX; + dc->vportExtY = oldvportExtY; + dc->vportOrgX = oldvportOrgX; + dc->vportOrgY = oldvportOrgY; + /* release DC */ + GDI_ReleaseObj(hdc); + SetWorldTransform(hdc, &savedXform); + SetEMFTransform(hdc, &savedEMFXform); + if (savedMode) SetGraphicsMode(hdc, savedMode); }