Commit c871d9a8 authored by Dmitry Timoshkov's avatar Dmitry Timoshkov Committed by Alexandre Julliard

gdi32: Save/restore internal EMF playing state on EMR_SAVEDC/EMR_RESTOREDC, add a test for this.

parent d01438bd
...@@ -491,10 +491,9 @@ UINT WINAPI GetEnhMetaFileBits( ...@@ -491,10 +491,9 @@ UINT WINAPI GetEnhMetaFileBits(
return size; return size;
} }
typedef struct enum_emh_data typedef struct EMF_dc_state
{ {
INT mode; INT mode;
XFORM init_transform;
XFORM world_transform; XFORM world_transform;
INT wndOrgX; INT wndOrgX;
INT wndOrgY; INT wndOrgY;
...@@ -504,6 +503,15 @@ typedef struct enum_emh_data ...@@ -504,6 +503,15 @@ typedef struct enum_emh_data
INT vportOrgY; INT vportOrgY;
INT vportExtX; INT vportExtX;
INT vportExtY; INT vportExtY;
struct EMF_dc_state *next;
} EMF_dc_state;
typedef struct enum_emh_data
{
XFORM init_transform;
EMF_dc_state state;
INT save_level;
EMF_dc_state *saved_state;
} enum_emh_data; } enum_emh_data;
#define ENUM_GET_PRIVATE_DATA(ht) \ #define ENUM_GET_PRIVATE_DATA(ht) \
...@@ -519,16 +527,16 @@ static void EMF_Update_MF_Xform(HDC hdc, const enum_emh_data *info) ...@@ -519,16 +527,16 @@ static void EMF_Update_MF_Xform(HDC hdc, const enum_emh_data *info)
XFORM mapping_mode_trans, final_trans; XFORM mapping_mode_trans, final_trans;
FLOAT scaleX, scaleY; FLOAT scaleX, scaleY;
scaleX = (FLOAT)info->vportExtX / (FLOAT)info->wndExtX; scaleX = (FLOAT)info->state.vportExtX / (FLOAT)info->state.wndExtX;
scaleY = (FLOAT)info->vportExtY / (FLOAT)info->wndExtY; scaleY = (FLOAT)info->state.vportExtY / (FLOAT)info->state.wndExtY;
mapping_mode_trans.eM11 = scaleX; mapping_mode_trans.eM11 = scaleX;
mapping_mode_trans.eM12 = 0.0; mapping_mode_trans.eM12 = 0.0;
mapping_mode_trans.eM21 = 0.0; mapping_mode_trans.eM21 = 0.0;
mapping_mode_trans.eM22 = scaleY; mapping_mode_trans.eM22 = scaleY;
mapping_mode_trans.eDx = (FLOAT)info->vportOrgX - scaleX * (FLOAT)info->wndOrgX; mapping_mode_trans.eDx = (FLOAT)info->state.vportOrgX - scaleX * (FLOAT)info->state.wndOrgX;
mapping_mode_trans.eDy = (FLOAT)info->vportOrgY - scaleY * (FLOAT)info->wndOrgY; mapping_mode_trans.eDy = (FLOAT)info->state.vportOrgY - scaleY * (FLOAT)info->state.wndOrgY;
CombineTransform(&final_trans, &info->world_transform, &mapping_mode_trans); CombineTransform(&final_trans, &info->state.world_transform, &mapping_mode_trans);
CombineTransform(&final_trans, &final_trans, &info->init_transform); CombineTransform(&final_trans, &final_trans, &info->init_transform);
if (!SetWorldTransform(hdc, &final_trans)) if (!SetWorldTransform(hdc, &final_trans))
...@@ -537,6 +545,40 @@ static void EMF_Update_MF_Xform(HDC hdc, const enum_emh_data *info) ...@@ -537,6 +545,40 @@ static void EMF_Update_MF_Xform(HDC hdc, const enum_emh_data *info)
} }
} }
static void EMF_RestoreDC( enum_emh_data *info, INT level )
{
if (abs(level) > info->save_level || level == 0) return;
if (level < 0) level = info->save_level + level + 1;
while (info->save_level >= level)
{
EMF_dc_state *state = info->saved_state;
info->saved_state = state->next;
state->next = NULL;
if (--info->save_level < level)
{
EMF_dc_state *next = info->state.next;
info->state = *state;
info->state.next = next;
}
HeapFree( GetProcessHeap(), 0, state );
}
}
static void EMF_SaveDC( enum_emh_data *info )
{
EMF_dc_state *state = HeapAlloc( GetProcessHeap(), 0, sizeof(*state));
if (state)
{
*state = info->state;
state->next = info->saved_state;
info->saved_state = state;
info->save_level++;
TRACE("save_level %d\n", info->save_level);
}
}
static void EMF_SetMapMode(HDC hdc, enum_emh_data *info) static void EMF_SetMapMode(HDC hdc, enum_emh_data *info)
{ {
INT horzSize = GetDeviceCaps( hdc, HORZSIZE ); INT horzSize = GetDeviceCaps( hdc, HORZSIZE );
...@@ -544,46 +586,46 @@ static void EMF_SetMapMode(HDC hdc, enum_emh_data *info) ...@@ -544,46 +586,46 @@ static void EMF_SetMapMode(HDC hdc, enum_emh_data *info)
INT horzRes = GetDeviceCaps( hdc, HORZRES ); INT horzRes = GetDeviceCaps( hdc, HORZRES );
INT vertRes = GetDeviceCaps( hdc, VERTRES ); INT vertRes = GetDeviceCaps( hdc, VERTRES );
TRACE("%d\n",info->mode); TRACE("%d\n", info->state.mode);
switch(info->mode) switch(info->state.mode)
{ {
case MM_TEXT: case MM_TEXT:
info->wndExtX = 1; info->state.wndExtX = 1;
info->wndExtY = 1; info->state.wndExtY = 1;
info->vportExtX = 1; info->state.vportExtX = 1;
info->vportExtY = 1; info->state.vportExtY = 1;
break; break;
case MM_LOMETRIC: case MM_LOMETRIC:
case MM_ISOTROPIC: case MM_ISOTROPIC:
info->wndExtX = horzSize * 10; info->state.wndExtX = horzSize * 10;
info->wndExtY = vertSize * 10; info->state.wndExtY = vertSize * 10;
info->vportExtX = horzRes; info->state.vportExtX = horzRes;
info->vportExtY = -vertRes; info->state.vportExtY = -vertRes;
break; break;
case MM_HIMETRIC: case MM_HIMETRIC:
info->wndExtX = horzSize * 100; info->state.wndExtX = horzSize * 100;
info->wndExtY = vertSize * 100; info->state.wndExtY = vertSize * 100;
info->vportExtX = horzRes; info->state.vportExtX = horzRes;
info->vportExtY = -vertRes; info->state.vportExtY = -vertRes;
break; break;
case MM_LOENGLISH: case MM_LOENGLISH:
info->wndExtX = MulDiv(1000, horzSize, 254); info->state.wndExtX = MulDiv(1000, horzSize, 254);
info->wndExtY = MulDiv(1000, vertSize, 254); info->state.wndExtY = MulDiv(1000, vertSize, 254);
info->vportExtX = horzRes; info->state.vportExtX = horzRes;
info->vportExtY = -vertRes; info->state.vportExtY = -vertRes;
break; break;
case MM_HIENGLISH: case MM_HIENGLISH:
info->wndExtX = MulDiv(10000, horzSize, 254); info->state.wndExtX = MulDiv(10000, horzSize, 254);
info->wndExtY = MulDiv(10000, vertSize, 254); info->state.wndExtY = MulDiv(10000, vertSize, 254);
info->vportExtX = horzRes; info->state.vportExtX = horzRes;
info->vportExtY = -vertRes; info->state.vportExtY = -vertRes;
break; break;
case MM_TWIPS: case MM_TWIPS:
info->wndExtX = MulDiv(14400, horzSize, 254); info->state.wndExtX = MulDiv(14400, horzSize, 254);
info->wndExtY = MulDiv(14400, vertSize, 254); info->state.wndExtY = MulDiv(14400, vertSize, 254);
info->vportExtX = horzRes; info->state.vportExtX = horzRes;
info->vportExtY = -vertRes; info->state.vportExtY = -vertRes;
break; break;
case MM_ANISOTROPIC: case MM_ANISOTROPIC:
break; break;
...@@ -600,22 +642,22 @@ static void EMF_SetMapMode(HDC hdc, enum_emh_data *info) ...@@ -600,22 +642,22 @@ static void EMF_SetMapMode(HDC hdc, enum_emh_data *info)
static void EMF_FixIsotropic(HDC hdc, enum_emh_data *info) static void EMF_FixIsotropic(HDC hdc, enum_emh_data *info)
{ {
double xdim = fabs((double)info->vportExtX * GetDeviceCaps( hdc, HORZSIZE ) / double xdim = fabs((double)info->state.vportExtX * GetDeviceCaps( hdc, HORZSIZE ) /
(GetDeviceCaps( hdc, HORZRES ) * info->wndExtX)); (GetDeviceCaps( hdc, HORZRES ) * info->state.wndExtX));
double ydim = fabs((double)info->vportExtY * GetDeviceCaps( hdc, VERTSIZE ) / double ydim = fabs((double)info->state.vportExtY * GetDeviceCaps( hdc, VERTSIZE ) /
(GetDeviceCaps( hdc, VERTRES ) * info->wndExtY)); (GetDeviceCaps( hdc, VERTRES ) * info->state.wndExtY));
if (xdim > ydim) if (xdim > ydim)
{ {
INT mincx = (info->vportExtX >= 0) ? 1 : -1; INT mincx = (info->state.vportExtX >= 0) ? 1 : -1;
info->vportExtX = floor(info->vportExtX * ydim / xdim + 0.5); info->state.vportExtX = floor(info->state.vportExtX * ydim / xdim + 0.5);
if (!info->vportExtX) info->vportExtX = mincx; if (!info->state.vportExtX) info->state.vportExtX = mincx;
} }
else else
{ {
INT mincy = (info->vportExtY >= 0) ? 1 : -1; INT mincy = (info->state.vportExtY >= 0) ? 1 : -1;
info->vportExtY = floor(info->vportExtY * xdim / ydim + 0.5); info->state.vportExtY = floor(info->state.vportExtY * xdim / ydim + 0.5);
if (!info->vportExtY) info->vportExtY = mincy; if (!info->state.vportExtY) info->state.vportExtY = mincy;
} }
} }
...@@ -740,9 +782,10 @@ BOOL WINAPI PlayEnhMetaFileRecord( ...@@ -740,9 +782,10 @@ BOOL WINAPI PlayEnhMetaFileRecord(
{ {
const EMRSETMAPMODE *pSetMapMode = (const EMRSETMAPMODE *)mr; const EMRSETMAPMODE *pSetMapMode = (const EMRSETMAPMODE *)mr;
if(info->mode == pSetMapMode->iMode && (info->mode == MM_ISOTROPIC || info->mode == MM_ANISOTROPIC)) if (info->state.mode == pSetMapMode->iMode &&
(info->state.mode == MM_ISOTROPIC || info->state.mode == MM_ANISOTROPIC))
break; break;
info->mode = pSetMapMode->iMode; info->state.mode = pSetMapMode->iMode;
EMF_SetMapMode(hdc, info); EMF_SetMapMode(hdc, info);
break; break;
} }
...@@ -790,14 +833,16 @@ BOOL WINAPI PlayEnhMetaFileRecord( ...@@ -790,14 +833,16 @@ BOOL WINAPI PlayEnhMetaFileRecord(
} }
case EMR_SAVEDC: case EMR_SAVEDC:
{ {
SaveDC(hdc); if (SaveDC( hdc ))
EMF_SaveDC( info );
break; break;
} }
case EMR_RESTOREDC: case EMR_RESTOREDC:
{ {
const EMRRESTOREDC *pRestoreDC = (const EMRRESTOREDC *)mr; const EMRRESTOREDC *pRestoreDC = (const EMRRESTOREDC *)mr;
TRACE("EMR_RESTORE: %d\n", pRestoreDC->iRelative); TRACE("EMR_RESTORE: %d\n", pRestoreDC->iRelative);
RestoreDC(hdc, pRestoreDC->iRelative); if (RestoreDC( hdc, pRestoreDC->iRelative ))
EMF_RestoreDC( info, pRestoreDC->iRelative );
break; break;
} }
case EMR_INTERSECTCLIPRECT: case EMR_INTERSECTCLIPRECT:
...@@ -839,48 +884,46 @@ BOOL WINAPI PlayEnhMetaFileRecord( ...@@ -839,48 +884,46 @@ BOOL WINAPI PlayEnhMetaFileRecord(
{ {
const EMRSETWINDOWORGEX *pSetWindowOrgEx = (const EMRSETWINDOWORGEX *)mr; const EMRSETWINDOWORGEX *pSetWindowOrgEx = (const EMRSETWINDOWORGEX *)mr;
info->wndOrgX = pSetWindowOrgEx->ptlOrigin.x; info->state.wndOrgX = pSetWindowOrgEx->ptlOrigin.x;
info->wndOrgY = pSetWindowOrgEx->ptlOrigin.y; info->state.wndOrgY = pSetWindowOrgEx->ptlOrigin.y;
TRACE("SetWindowOrgEx: %d,%d\n",info->wndOrgX,info->wndOrgY); TRACE("SetWindowOrgEx: %d,%d\n", info->state.wndOrgX, info->state.wndOrgY);
break; break;
} }
case EMR_SETWINDOWEXTEX: case EMR_SETWINDOWEXTEX:
{ {
const EMRSETWINDOWEXTEX *pSetWindowExtEx = (const EMRSETWINDOWEXTEX *)mr; const EMRSETWINDOWEXTEX *pSetWindowExtEx = (const EMRSETWINDOWEXTEX *)mr;
if(info->mode != MM_ISOTROPIC && info->mode != MM_ANISOTROPIC) if (info->state.mode != MM_ISOTROPIC && info->state.mode != MM_ANISOTROPIC)
break; break;
info->wndExtX = pSetWindowExtEx->szlExtent.cx; info->state.wndExtX = pSetWindowExtEx->szlExtent.cx;
info->wndExtY = pSetWindowExtEx->szlExtent.cy; info->state.wndExtY = pSetWindowExtEx->szlExtent.cy;
if (info->mode == MM_ISOTROPIC) if (info->state.mode == MM_ISOTROPIC)
EMF_FixIsotropic(hdc, info); EMF_FixIsotropic(hdc, info);
TRACE("SetWindowExtEx: %d,%d\n",info->wndExtX,info->wndExtY); TRACE("SetWindowExtEx: %d,%d\n",info->state.wndExtX, info->state.wndExtY);
break; break;
} }
case EMR_SETVIEWPORTORGEX: case EMR_SETVIEWPORTORGEX:
{ {
const EMRSETVIEWPORTORGEX *pSetViewportOrgEx = (const EMRSETVIEWPORTORGEX *)mr; const EMRSETVIEWPORTORGEX *pSetViewportOrgEx = (const EMRSETVIEWPORTORGEX *)mr;
enum_emh_data *info = ENUM_GET_PRIVATE_DATA(handletable);
info->vportOrgX = pSetViewportOrgEx->ptlOrigin.x; info->state.vportOrgX = pSetViewportOrgEx->ptlOrigin.x;
info->vportOrgY = pSetViewportOrgEx->ptlOrigin.y; info->state.vportOrgY = pSetViewportOrgEx->ptlOrigin.y;
TRACE("SetViewportOrgEx: %d,%d\n",info->vportOrgX,info->vportOrgY); TRACE("SetViewportOrgEx: %d,%d\n", info->state.vportOrgX, info->state.vportOrgY);
break; break;
} }
case EMR_SETVIEWPORTEXTEX: case EMR_SETVIEWPORTEXTEX:
{ {
const EMRSETVIEWPORTEXTEX *pSetViewportExtEx = (const EMRSETVIEWPORTEXTEX *)mr; const EMRSETVIEWPORTEXTEX *pSetViewportExtEx = (const EMRSETVIEWPORTEXTEX *)mr;
enum_emh_data *info = ENUM_GET_PRIVATE_DATA(handletable);
if(info->mode != MM_ISOTROPIC && info->mode != MM_ANISOTROPIC) if (info->state.mode != MM_ISOTROPIC && info->state.mode != MM_ANISOTROPIC)
break; break;
info->vportExtX = pSetViewportExtEx->szlExtent.cx; info->state.vportExtX = pSetViewportExtEx->szlExtent.cx;
info->vportExtY = pSetViewportExtEx->szlExtent.cy; info->state.vportExtY = pSetViewportExtEx->szlExtent.cy;
if (info->mode == MM_ISOTROPIC) if (info->state.mode == MM_ISOTROPIC)
EMF_FixIsotropic(hdc, info); EMF_FixIsotropic(hdc, info);
TRACE("SetViewportExtEx: %d,%d\n",info->vportExtX,info->vportExtY); TRACE("SetViewportExtEx: %d,%d\n", info->state.vportExtX, info->state.vportExtY);
break; break;
} }
case EMR_CREATEPEN: case EMR_CREATEPEN:
...@@ -1193,7 +1236,7 @@ BOOL WINAPI PlayEnhMetaFileRecord( ...@@ -1193,7 +1236,7 @@ BOOL WINAPI PlayEnhMetaFileRecord(
case EMR_SETWORLDTRANSFORM: case EMR_SETWORLDTRANSFORM:
{ {
const EMRSETWORLDTRANSFORM *lpXfrm = (const EMRSETWORLDTRANSFORM *)mr; const EMRSETWORLDTRANSFORM *lpXfrm = (const EMRSETWORLDTRANSFORM *)mr;
info->world_transform = lpXfrm->xform; info->state.world_transform = lpXfrm->xform;
break; break;
} }
...@@ -1331,18 +1374,18 @@ BOOL WINAPI PlayEnhMetaFileRecord( ...@@ -1331,18 +1374,18 @@ BOOL WINAPI PlayEnhMetaFileRecord(
{ {
const EMRSCALEVIEWPORTEXTEX *lpScaleViewportExtEx = (const EMRSCALEVIEWPORTEXTEX *)mr; const EMRSCALEVIEWPORTEXTEX *lpScaleViewportExtEx = (const EMRSCALEVIEWPORTEXTEX *)mr;
if ((info->mode != MM_ISOTROPIC) && (info->mode != MM_ANISOTROPIC)) if ((info->state.mode != MM_ISOTROPIC) && (info->state.mode != MM_ANISOTROPIC))
break; break;
if (!lpScaleViewportExtEx->xNum || !lpScaleViewportExtEx->xDenom || if (!lpScaleViewportExtEx->xNum || !lpScaleViewportExtEx->xDenom ||
!lpScaleViewportExtEx->yNum || !lpScaleViewportExtEx->yDenom) !lpScaleViewportExtEx->yNum || !lpScaleViewportExtEx->yDenom)
break; break;
info->vportExtX = MulDiv(info->vportExtX, lpScaleViewportExtEx->xNum, info->state.vportExtX = MulDiv(info->state.vportExtX, lpScaleViewportExtEx->xNum,
lpScaleViewportExtEx->xDenom); lpScaleViewportExtEx->xDenom);
info->vportExtY = MulDiv(info->vportExtY, lpScaleViewportExtEx->yNum, info->state.vportExtY = MulDiv(info->state.vportExtY, lpScaleViewportExtEx->yNum,
lpScaleViewportExtEx->yDenom); lpScaleViewportExtEx->yDenom);
if (info->vportExtX == 0) info->vportExtX = 1; if (info->state.vportExtX == 0) info->state.vportExtX = 1;
if (info->vportExtY == 0) info->vportExtY = 1; if (info->state.vportExtY == 0) info->state.vportExtY = 1;
if (info->mode == MM_ISOTROPIC) if (info->state.mode == MM_ISOTROPIC)
EMF_FixIsotropic(hdc, info); EMF_FixIsotropic(hdc, info);
TRACE("EMRSCALEVIEWPORTEXTEX %d/%d %d/%d\n", TRACE("EMRSCALEVIEWPORTEXTEX %d/%d %d/%d\n",
...@@ -1356,18 +1399,18 @@ BOOL WINAPI PlayEnhMetaFileRecord( ...@@ -1356,18 +1399,18 @@ BOOL WINAPI PlayEnhMetaFileRecord(
{ {
const EMRSCALEWINDOWEXTEX *lpScaleWindowExtEx = (const EMRSCALEWINDOWEXTEX *)mr; const EMRSCALEWINDOWEXTEX *lpScaleWindowExtEx = (const EMRSCALEWINDOWEXTEX *)mr;
if ((info->mode != MM_ISOTROPIC) && (info->mode != MM_ANISOTROPIC)) if ((info->state.mode != MM_ISOTROPIC) && (info->state.mode != MM_ANISOTROPIC))
break; break;
if (!lpScaleWindowExtEx->xNum || !lpScaleWindowExtEx->xDenom || if (!lpScaleWindowExtEx->xNum || !lpScaleWindowExtEx->xDenom ||
!lpScaleWindowExtEx->xNum || !lpScaleWindowExtEx->yDenom) !lpScaleWindowExtEx->xNum || !lpScaleWindowExtEx->yDenom)
break; break;
info->wndExtX = MulDiv(info->wndExtX, lpScaleWindowExtEx->xNum, info->state.wndExtX = MulDiv(info->state.wndExtX, lpScaleWindowExtEx->xNum,
lpScaleWindowExtEx->xDenom); lpScaleWindowExtEx->xDenom);
info->wndExtY = MulDiv(info->wndExtY, lpScaleWindowExtEx->yNum, info->state.wndExtY = MulDiv(info->state.wndExtY, lpScaleWindowExtEx->yNum,
lpScaleWindowExtEx->yDenom); lpScaleWindowExtEx->yDenom);
if (info->wndExtX == 0) info->wndExtX = 1; if (info->state.wndExtX == 0) info->state.wndExtX = 1;
if (info->wndExtY == 0) info->wndExtY = 1; if (info->state.wndExtY == 0) info->state.wndExtY = 1;
if (info->mode == MM_ISOTROPIC) if (info->state.mode == MM_ISOTROPIC)
EMF_FixIsotropic(hdc, info); EMF_FixIsotropic(hdc, info);
TRACE("EMRSCALEWINDOWEXTEX %d/%d %d/%d\n", TRACE("EMRSCALEWINDOWEXTEX %d/%d %d/%d\n",
...@@ -1383,16 +1426,16 @@ BOOL WINAPI PlayEnhMetaFileRecord( ...@@ -1383,16 +1426,16 @@ BOOL WINAPI PlayEnhMetaFileRecord(
switch(lpModifyWorldTrans->iMode) { switch(lpModifyWorldTrans->iMode) {
case MWT_IDENTITY: case MWT_IDENTITY:
info->world_transform.eM11 = info->world_transform.eM22 = 1; info->state.world_transform.eM11 = info->state.world_transform.eM22 = 1;
info->world_transform.eM12 = info->world_transform.eM21 = 0; info->state.world_transform.eM12 = info->state.world_transform.eM21 = 0;
info->world_transform.eDx = info->world_transform.eDy = 0; info->state.world_transform.eDx = info->state.world_transform.eDy = 0;
break; break;
case MWT_LEFTMULTIPLY: case MWT_LEFTMULTIPLY:
CombineTransform(&info->world_transform, &lpModifyWorldTrans->xform, CombineTransform(&info->state.world_transform, &lpModifyWorldTrans->xform,
&info->world_transform); &info->state.world_transform);
break; break;
case MWT_RIGHTMULTIPLY: case MWT_RIGHTMULTIPLY:
CombineTransform(&info->world_transform, &info->world_transform, CombineTransform(&info->state.world_transform, &info->state.world_transform,
&lpModifyWorldTrans->xform); &lpModifyWorldTrans->xform);
break; break;
default: default:
...@@ -2243,17 +2286,20 @@ BOOL WINAPI EnumEnhMetaFile( ...@@ -2243,17 +2286,20 @@ BOOL WINAPI EnumEnhMetaFile(
SetLastError(ERROR_NOT_ENOUGH_MEMORY); SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE; return FALSE;
} }
info->wndOrgX = 0; info->state.wndOrgX = 0;
info->wndOrgY = 0; info->state.wndOrgY = 0;
info->wndExtX = 1; info->state.wndExtX = 1;
info->wndExtY = 1; info->state.wndExtY = 1;
info->vportOrgX = 0; info->state.vportOrgX = 0;
info->vportOrgY = 0; info->state.vportOrgY = 0;
info->vportExtX = 1; info->state.vportExtX = 1;
info->vportExtY = 1; info->state.vportExtY = 1;
info->world_transform.eM11 = info->world_transform.eM22 = 1; info->state.world_transform.eM11 = info->state.world_transform.eM22 = 1;
info->world_transform.eM12 = info->world_transform.eM21 = 0; info->state.world_transform.eM12 = info->state.world_transform.eM21 = 0;
info->world_transform.eDx = info->world_transform.eDy = 0; info->state.world_transform.eDx = info->state.world_transform.eDy = 0;
info->save_level = 0;
info->saved_state = NULL;
ht = (HANDLETABLE*) &info[1]; ht = (HANDLETABLE*) &info[1];
ht->objectHandle[0] = hmf; ht->objectHandle[0] = hmf;
...@@ -2282,7 +2328,7 @@ BOOL WINAPI EnumEnhMetaFile( ...@@ -2282,7 +2328,7 @@ BOOL WINAPI EnumEnhMetaFile(
old_stretchblt = SetStretchBltMode(hdc, BLACKONWHITE); old_stretchblt = SetStretchBltMode(hdc, BLACKONWHITE);
} }
info->mode = MM_TEXT; info->state.mode = MM_TEXT;
if ( IS_WIN9X() ) if ( IS_WIN9X() )
{ {
...@@ -2386,6 +2432,12 @@ BOOL WINAPI EnumEnhMetaFile( ...@@ -2386,6 +2432,12 @@ BOOL WINAPI EnumEnhMetaFile(
if( (ht->objectHandle)[i] ) if( (ht->objectHandle)[i] )
DeleteObject( (ht->objectHandle)[i] ); DeleteObject( (ht->objectHandle)[i] );
while (info->saved_state)
{
EMF_dc_state *state = info->saved_state;
info->saved_state = info->saved_state->next;
HeapFree( GetProcessHeap(), 0, state );
}
HeapFree( GetProcessHeap(), 0, info ); HeapFree( GetProcessHeap(), 0, info );
return ret; return ret;
} }
......
...@@ -261,37 +261,174 @@ static void test_ExtTextOut(void) ...@@ -261,37 +261,174 @@ static void test_ExtTextOut(void)
DestroyWindow(hwnd); DestroyWindow(hwnd);
} }
static void check_dc_state(HDC hdc, int restore_no,
int wnd_org_x, int wnd_org_y, int wnd_ext_x, int wnd_ext_y,
int vp_org_x, int vp_org_y, int vp_ext_x, int vp_ext_y)
{
BOOL ret;
XFORM xform;
POINT vp_org, win_org;
SIZE vp_size, win_size;
FLOAT xscale, yscale, edx, edy;
SetLastError(0xdeadbeef);
ret = GetWorldTransform(hdc, &xform);
if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) goto win9x_here;
ok(ret, "GetWorldTransform error %u\n", GetLastError());
trace("%d: eM11 %f, eM22 %f, eDx %f, eDy %f\n", restore_no, xform.eM11, xform.eM22, xform.eDx, xform.eDy);
ok(xform.eM12 == 0.0, "%d: expected eM12 0.0, got %f\n", restore_no, xform.eM12);
ok(xform.eM21 == 0.0, "%d: expected eM21 0.0, got %f\n", restore_no, xform.eM21);
xscale = (FLOAT)vp_ext_x / (FLOAT)wnd_ext_x;
trace("x scale %f\n", xscale);
ok(fabs(xscale - xform.eM11) < 0.01, "%d: vp_ext_x %d, wnd_ext_cx %d, eM11 %f\n",
restore_no, vp_ext_x, wnd_ext_x, xform.eM11);
yscale = (FLOAT)vp_ext_y / (FLOAT)wnd_ext_y;
trace("y scale %f\n", yscale);
ok(fabs(yscale - xform.eM22) < 0.01, "%d: vp_ext_y %d, wnd_ext_y %d, eM22 %f\n",
restore_no, vp_ext_y, wnd_ext_y, xform.eM22);
edx = (FLOAT)vp_org_x - xform.eM11 * (FLOAT)wnd_org_x;
ok(fabs(edx - xform.eDx) < 0.01, "%d: edx %f != eDx %f\n", restore_no, edx, xform.eDx);
edy = (FLOAT)vp_org_y - xform.eM22 * (FLOAT)wnd_org_y;
ok(fabs(edy - xform.eDy) < 0.01, "%d: edy %f != eDy %f\n", restore_no, edy, xform.eDy);
return;
win9x_here:
GetWindowOrgEx(hdc, &win_org);
GetViewportOrgEx(hdc, &vp_org);
GetWindowExtEx(hdc, &win_size);
GetViewportExtEx(hdc, &vp_size);
ok(wnd_org_x == win_org.x, "%d: wnd_org_x: %d != %d\n", restore_no, wnd_org_x, win_org.x);
ok(wnd_org_y == win_org.y, "%d: wnd_org_y: %d != %d\n", restore_no, wnd_org_y, win_org.y);
ok(vp_org_x == vp_org.x, "%d: vport_org_x: %d != %d\n", restore_no, vp_org_x, vp_org.x);
ok(vp_org_y == vp_org.y, "%d: vport_org_y: %d != %d\n", restore_no, vp_org_y, vp_org.y);
ok(wnd_ext_x == win_size.cx, "%d: wnd_ext_x: %d != %d\n", restore_no, wnd_ext_x, win_size.cx);
ok(wnd_ext_y == win_size.cy, "%d: wnd_ext_y: %d != %d\n", restore_no, wnd_ext_y, win_size.cy);
ok(vp_ext_x == vp_size.cx, "%d: vport_ext_x: %d != %d\n", restore_no, vp_ext_x, vp_size.cx);
ok(vp_ext_y == vp_size.cy, "%d: vport_ext_y: %d != %d\n", restore_no, vp_ext_y, vp_size.cy);
}
static int CALLBACK savedc_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table, static int CALLBACK savedc_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
const ENHMETARECORD *emr, int n_objs, LPARAM param) const ENHMETARECORD *emr, int n_objs, LPARAM param)
{ {
BOOL ret;
XFORM xform;
POINT pt;
SIZE size;
static int save_state; static int save_state;
static int restore_no; static int restore_no;
trace("hdc %p, emr->iType %d, emr->nSize %d, param %p\n",
hdc, emr->iType, emr->nSize, (void *)param);
trace("BEFORE:\n");
SetLastError(0xdeadbeef);
ret = GetWorldTransform(hdc, &xform);
if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
{
ok(GetWindowOrgEx(hdc, &pt), "GetWindowOrgEx error %u\n", GetLastError());
trace("window org (%d,%d)\n", pt.x, pt.y);
ok(GetViewportOrgEx(hdc, &pt), "GetViewportOrgEx error %u\n", GetLastError());
trace("vport org (%d,%d)\n", pt.x, pt.y);
ok(GetWindowExtEx(hdc, &size), "GetWindowExtEx error %u\n", GetLastError());
trace("window ext (%d,%d)\n", size.cx, size.cy);
ok(GetViewportExtEx(hdc, &size), "GetViewportExtEx error %u\n", GetLastError());
trace("vport ext (%d,%d)\n", size.cx, size.cy);
}
else
{
ok(ret, "GetWorldTransform error %u\n", GetLastError());
trace("eM11 %f, eM22 %f, eDx %f, eDy %f\n", xform.eM11, xform.eM22, xform.eDx, xform.eDy);
}
PlayEnhMetaFileRecord(hdc, handle_table, emr, n_objs);
switch (emr->iType) switch (emr->iType)
{ {
case EMR_HEADER: case EMR_HEADER:
{
static RECT exp_bounds = { 0, 0, 150, 150 };
RECT bounds;
const ENHMETAHEADER *emf = (const ENHMETAHEADER *)emr;
trace("bounds %d,%d-%d,%d, frame %d,%d-%d,%d\n",
emf->rclBounds.left, emf->rclBounds.top, emf->rclBounds.right, emf->rclBounds.bottom,
emf->rclFrame.left, emf->rclFrame.top, emf->rclFrame.right, emf->rclFrame.bottom);
trace("mm %d x %d, device %d x %d\n", emf->szlMillimeters.cx, emf->szlMillimeters.cy,
emf->szlDevice.cx, emf->szlDevice.cy);
SetRect(&bounds, emf->rclBounds.left, emf->rclBounds.top, emf->rclBounds.right, emf->rclBounds.bottom);
ok(EqualRect(&bounds, &exp_bounds), "wrong bounds\n");
save_state = 0; save_state = 0;
restore_no = 0; restore_no = 0;
check_dc_state(hdc, restore_no, 0, 0, 1, 1, 0, 0, 1, 1);
break; break;
}
case EMR_LINETO:
{
const EMRLINETO *line = (const EMRLINETO *)emr;
trace("EMR_LINETO %d,%d\n", line->ptl.x, line->ptl.x);
break;
}
case EMR_SETWINDOWORGEX:
{
const EMRSETWINDOWORGEX *org = (const EMRSETWINDOWORGEX *)emr;
trace("EMR_SETWINDOWORGEX: %d,%d\n", org->ptlOrigin.x, org->ptlOrigin.y);
break;
}
case EMR_SETWINDOWEXTEX:
{
const EMRSETWINDOWEXTEX *ext = (const EMRSETWINDOWEXTEX *)emr;
trace("EMR_SETWINDOWEXTEX: %d,%d\n", ext->szlExtent.cx, ext->szlExtent.cy);
break;
}
case EMR_SETVIEWPORTORGEX:
{
const EMRSETVIEWPORTORGEX *org = (const EMRSETVIEWPORTORGEX *)emr;
trace("EMR_SETVIEWPORTORGEX: %d,%d\n", org->ptlOrigin.x, org->ptlOrigin.y);
break;
}
case EMR_SETVIEWPORTEXTEX:
{
const EMRSETVIEWPORTEXTEX *ext = (const EMRSETVIEWPORTEXTEX *)emr;
trace("EMR_SETVIEWPORTEXTEX: %d,%d\n", ext->szlExtent.cx, ext->szlExtent.cy);
break;
}
case EMR_SAVEDC: case EMR_SAVEDC:
save_state++; save_state++;
trace("EMR_SAVEDC\n");
break; break;
case EMR_RESTOREDC: case EMR_RESTOREDC:
{ {
const EMRRESTOREDC *restoredc = (const EMRRESTOREDC *)emr; const EMRRESTOREDC *restoredc = (const EMRRESTOREDC *)emr;
trace("EMR_RESTOREDC: %d\n", restoredc->iRelative);
switch(++restore_no) switch(++restore_no)
{ {
case 1: case 1:
ok(restoredc->iRelative == -1, "first restore %d\n", restoredc->iRelative); ok(restoredc->iRelative == -1, "first restore %d\n", restoredc->iRelative);
check_dc_state(hdc, restore_no, -2, -2, 8192, 8192, 20, 20, 20479, 20478);
break; break;
case 2: case 2:
ok(restoredc->iRelative == -3, "second restore %d\n", restoredc->iRelative); ok(restoredc->iRelative == -3, "second restore %d\n", restoredc->iRelative);
check_dc_state(hdc, restore_no, 0, 0, 16384, 16384, 0, 0, 17873, 17872);
break; break;
case 3: case 3:
ok(restoredc->iRelative == -2, "third restore %d\n", restoredc->iRelative); ok(restoredc->iRelative == -2, "third restore %d\n", restoredc->iRelative);
check_dc_state(hdc, restore_no, -4, -4, 32767, 32767, 40, 40, 3276, 3276);
break; break;
} }
ok(restore_no <= 3, "restore_no %d\n", restore_no); ok(restore_no <= 3, "restore_no %d\n", restore_no);
...@@ -302,6 +439,27 @@ static int CALLBACK savedc_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table, ...@@ -302,6 +439,27 @@ static int CALLBACK savedc_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
ok(save_state == 0, "EOF save_state %d\n", save_state); ok(save_state == 0, "EOF save_state %d\n", save_state);
break; break;
} }
trace("AFTER:\n");
SetLastError(0xdeadbeef);
ret = GetWorldTransform(hdc, &xform);
if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
{
ok(GetWindowOrgEx(hdc, &pt), "GetWindowOrgEx error %u\n", GetLastError());
trace("window org (%d,%d)\n", pt.x, pt.y);
ok(GetViewportOrgEx(hdc, &pt), "GetViewportOrgEx error %u\n", GetLastError());
trace("vport org (%d,%d)\n", pt.x, pt.y);
ok(GetWindowExtEx(hdc, &size), "GetWindowExtEx error %u\n", GetLastError());
trace("window ext (%d,%d)\n", size.cx, size.cy);
ok(GetViewportExtEx(hdc, &size), "GetViewportExtEx error %u\n", GetLastError());
trace("vport ext (%d,%d)\n", size.cx, size.cy);
}
else
{
ok(ret, "GetWorldTransform error %u\n", GetLastError());
trace("eM11 %f, eM22 %f, eDx %f, eDy %f\n", xform.eM11, xform.eM22, xform.eDx, xform.eDy);
}
return 1; return 1;
} }
...@@ -311,7 +469,7 @@ static void test_SaveDC(void) ...@@ -311,7 +469,7 @@ static void test_SaveDC(void)
HENHMETAFILE hMetafile; HENHMETAFILE hMetafile;
HWND hwnd; HWND hwnd;
int ret; int ret;
static const RECT rc = { 0, 0, 100, 100 }; static const RECT rc = { 0, 0, 150, 150 };
/* Win9x doesn't play EMFs on invisible windows */ /* Win9x doesn't play EMFs on invisible windows */
hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE, hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
...@@ -324,18 +482,52 @@ static void test_SaveDC(void) ...@@ -324,18 +482,52 @@ static void test_SaveDC(void)
hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL); hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL);
ok(hdcMetafile != 0, "CreateEnhMetaFileA error %d\n", GetLastError()); ok(hdcMetafile != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
SetMapMode(hdcMetafile, MM_ANISOTROPIC);
/* Need to write something to the emf, otherwise Windows won't play it back */ /* Need to write something to the emf, otherwise Windows won't play it back */
LineTo(hdcMetafile, 100, 100); LineTo(hdcMetafile, 150, 150);
SetWindowOrgEx(hdcMetafile, 0, 0, NULL);
SetViewportOrgEx(hdcMetafile, 0, 0, NULL);
SetWindowExtEx(hdcMetafile, 110, 110, NULL );
SetViewportExtEx(hdcMetafile, 120, 120, NULL );
/* Force Win9x to update DC state */
SetPixelV(hdcMetafile, 50, 50, 0);
ret = SaveDC(hdcMetafile); ret = SaveDC(hdcMetafile);
ok(ret == 1, "ret = %d\n", ret); ok(ret == 1, "ret = %d\n", ret);
SetWindowOrgEx(hdcMetafile, -1, -1, NULL);
SetViewportOrgEx(hdcMetafile, 10, 10, NULL);
SetWindowExtEx(hdcMetafile, 150, 150, NULL );
SetViewportExtEx(hdcMetafile, 200, 200, NULL );
/* Force Win9x to update DC state */
SetPixelV(hdcMetafile, 50, 50, 0);
ret = SaveDC(hdcMetafile); ret = SaveDC(hdcMetafile);
ok(ret == 2, "ret = %d\n", ret); ok(ret == 2, "ret = %d\n", ret);
SetWindowOrgEx(hdcMetafile, -2, -2, NULL);
SetViewportOrgEx(hdcMetafile, 20, 20, NULL);
SetWindowExtEx(hdcMetafile, 120, 120, NULL );
SetViewportExtEx(hdcMetafile, 300, 300, NULL );
/* Force Win9x to update DC state */
SetPixelV(hdcMetafile, 50, 50, 0);
ret = SaveDC(hdcMetafile); ret = SaveDC(hdcMetafile);
ok(ret == 3, "ret = %d\n", ret); ok(ret == 3, "ret = %d\n", ret);
SetWindowOrgEx(hdcMetafile, -3, -3, NULL);
SetViewportOrgEx(hdcMetafile, 30, 30, NULL);
SetWindowExtEx(hdcMetafile, 200, 200, NULL );
SetViewportExtEx(hdcMetafile, 400, 400, NULL );
/* Force Win9x to update DC state */
SetPixelV(hdcMetafile, 50, 50, 0);
ret = RestoreDC(hdcMetafile, -1); ret = RestoreDC(hdcMetafile, -1);
ok(ret, "ret = %d\n", ret); ok(ret, "ret = %d\n", ret);
...@@ -345,6 +537,14 @@ static void test_SaveDC(void) ...@@ -345,6 +537,14 @@ static void test_SaveDC(void)
ret = RestoreDC(hdcMetafile, 1); ret = RestoreDC(hdcMetafile, 1);
ok(ret, "ret = %d\n", ret); ok(ret, "ret = %d\n", ret);
SetWindowOrgEx(hdcMetafile, -4, -4, NULL);
SetViewportOrgEx(hdcMetafile, 40, 40, NULL);
SetWindowExtEx(hdcMetafile, 500, 500, NULL );
SetViewportExtEx(hdcMetafile, 50, 50, NULL );
/* Force Win9x to update DC state */
SetPixelV(hdcMetafile, 50, 50, 0);
ret = SaveDC(hdcMetafile); ret = SaveDC(hdcMetafile);
ok(ret == 1, "ret = %d\n", ret); ok(ret == 1, "ret = %d\n", ret);
...@@ -1282,12 +1482,16 @@ static int CALLBACK clip_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table, ...@@ -1282,12 +1482,16 @@ static int CALLBACK clip_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
rect = rgn2.data.rdh.rcBound; rect = rgn2.data.rdh.rcBound;
rc_transformed = *rc; rc_transformed = *rc;
translate((POINT *)&rc_transformed, 2, &xform); translate((POINT *)&rc_transformed, 2, &xform);
trace("transformed (%d,%d-%d,%d)\n", rc_transformed.left, rc_transformed.top,
rc_transformed.right, rc_transformed.bottom);
ok(EqualRect(&rect, &rc_transformed), "rects don't match\n"); ok(EqualRect(&rect, &rc_transformed), "rects don't match\n");
rect = *(const RECT *)rgn2.data.Buffer; rect = *(const RECT *)rgn2.data.Buffer;
trace("rect (%d,%d-%d,%d)\n", rect.left, rect.top, rect.right, rect.bottom); trace("rect (%d,%d-%d,%d)\n", rect.left, rect.top, rect.right, rect.bottom);
rc_transformed = *rc; rc_transformed = *rc;
translate((POINT *)&rc_transformed, 2, &xform); translate((POINT *)&rc_transformed, 2, &xform);
trace("transformed (%d,%d-%d,%d)\n", rc_transformed.left, rc_transformed.top,
rc_transformed.right, rc_transformed.bottom);
ok(EqualRect(&rect, &rc_transformed), "rects don't match\n"); ok(EqualRect(&rect, &rc_transformed), "rects don't match\n");
ok(rgn2.data.rdh.dwSize == sizeof(rgn1->data.rdh), "expected sizeof(rdh), got %u", rgn2.data.rdh.dwSize); ok(rgn2.data.rdh.dwSize == sizeof(rgn1->data.rdh), "expected sizeof(rdh), got %u", rgn2.data.rdh.dwSize);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment