Fix handling of relative state indices in RestoreDC.

Fix return value of SaveDC when writing to an emf.
Before writing the EMR_EOF record we should ensure that we clear the
state stack.
This commit is contained in:
Huw Davies 2005-10-31 10:05:52 +00:00 committed by Alexandre Julliard
parent be29e3708b
commit 0d23ac479b
7 changed files with 227 additions and 32 deletions

View File

@ -504,8 +504,9 @@ INT WINAPI SaveDC( HDC hdc )
if(dc->funcs->pSaveDC)
{
ret = dc->funcs->pSaveDC( dc->physDev );
if(ret)
ret = ++dc->saveLevel;
GDI_ReleaseObj( hdc );
/* FIXME: ret is just a success flag, we should return a proper value */
return ret;
}
@ -551,26 +552,24 @@ BOOL WINAPI RestoreDC( HDC hdc, INT level )
TRACE("%p %d\n", hdc, level );
dc = DC_GetDCUpdate( hdc );
if(!dc) return FALSE;
if(dc->funcs->pRestoreDC)
{
success = dc->funcs->pRestoreDC( dc->physDev, level );
GDI_ReleaseObj( hdc );
return success;
}
if (level == -1) level = dc->saveLevel;
if ((level < 1)
/* This pair of checks disagrees with MSDN "Platform SDK:
Windows GDI" July 2000 which says all negative values
for level will be interpreted as an instance relative
to the current state. Restricting it to just -1 does
not satisfy this */
|| (level > dc->saveLevel))
if(abs(level) > dc->saveLevel || level == 0)
{
GDI_ReleaseObj( hdc );
return FALSE;
}
if(dc->funcs->pRestoreDC)
{
success = dc->funcs->pRestoreDC( dc->physDev, level );
if(level < 0) level = dc->saveLevel + level + 1;
if(success)
dc->saveLevel = level - 1;
GDI_ReleaseObj( hdc );
return success;
}
if (level < 0) level = dc->saveLevel + level + 1;
success=TRUE;
while (dc->saveLevel >= level)
{

View File

@ -38,19 +38,15 @@ BOOL EMFDRV_RestoreDC( PHYSDEV dev, INT level )
emr.emr.iType = EMR_RESTOREDC;
emr.emr.nSize = sizeof(emr);
emr.iRelative = -1;
if (level == -1)
return EMFDRV_WriteRecord( dev, &emr.emr );
else if (level > 0 && level <= physDev->dc->saveLevel)
{
while (level >= physDev->dc->saveLevel)
{
EMFDRV_WriteRecord( dev, &emr.emr );
level--;
}
return TRUE;
}
return FALSE;
if (level < 0)
emr.iRelative = level;
else
emr.iRelative = level - physDev->dc->saveLevel - 1;
EMFDRV_WriteRecord( dev, &emr.emr );
return TRUE;
}
UINT EMFDRV_SetTextAlign( PHYSDEV dev, UINT align )

View File

@ -422,6 +422,9 @@ HENHMETAFILE WINAPI CloseEnhMetaFile(HDC hdc) /* [in] metafile DC */
if (!(dc = (DC *) GDI_GetObjPtr( hdc, ENHMETAFILE_DC_MAGIC ))) return 0;
physDev = (EMFDRV_PDEVICE *)dc->physDev;
if(dc->saveLevel)
RestoreDC(hdc, 1);
emr.emr.iType = EMR_EOF;
emr.emr.nSize = sizeof(emr);
emr.nPalEntries = 0;

View File

@ -2,6 +2,7 @@ Makefile
bitmap.ok
brush.ok
clipping.ok
dc.ok
gdiobj.ok
generated.ok
mapping.ok

View File

@ -9,6 +9,7 @@ CTESTS = \
bitmap.c \
brush.c \
clipping.c \
dc.c \
gdiobj.c \
generated.c \
mapping.c \

88
dlls/gdi/tests/dc.c Normal file
View File

@ -0,0 +1,88 @@
/*
* Unit tests for dc functions
*
* Copyright (c) 2005 Huw Davies
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <assert.h>
#include <stdio.h>
#include <math.h>
#include "wine/test.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "winerror.h"
void test_savedc(void)
{
HDC hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
int ret;
ok(hdc != NULL, "CreateDC rets %p\n", hdc);
ret = SaveDC(hdc);
ok(ret == 1, "ret = %d\n", ret);
ret = SaveDC(hdc);
ok(ret == 2, "ret = %d\n", ret);
ret = SaveDC(hdc);
ok(ret == 3, "ret = %d\n", ret);
ret = RestoreDC(hdc, -1);
ok(ret, "ret = %d\n", ret);
ret = SaveDC(hdc);
ok(ret == 3, "ret = %d\n", ret);
ret = RestoreDC(hdc, 1);
ok(ret, "ret = %d\n", ret);
ret = SaveDC(hdc);
ok(ret == 1, "ret = %d\n", ret);
ret = SaveDC(hdc);
ok(ret == 2, "ret = %d\n", ret);
ret = SaveDC(hdc);
ok(ret == 3, "ret = %d\n", ret);
ret = RestoreDC(hdc, -2);
ok(ret, "ret = %d\n", ret);
ret = SaveDC(hdc);
ok(ret == 2, "ret = %d\n", ret);
ret = RestoreDC(hdc, -2);
ok(ret, "ret = %d\n", ret);
ret = SaveDC(hdc);
ok(ret == 1, "ret = %d\n", ret);
ret = SaveDC(hdc);
ok(ret == 2, "ret = %d\n", ret);
ret = RestoreDC(hdc, -4);
ok(!ret, "ret = %d\n", ret);
ret = RestoreDC(hdc, 3);
ok(!ret, "ret = %d\n", ret);
/* Under win98 the following two succeed and both clear the save stack
ret = RestoreDC(hdc, -3);
ok(!ret, "ret = %d\n", ret);
ret = RestoreDC(hdc, 0);
ok(!ret, "ret = %d\n", ret);
*/
ret = RestoreDC(hdc, 1);
ok(ret, "ret = %d\n", ret);
DeleteDC(hdc);
}
START_TEST(dc)
{
test_savedc();
}

View File

@ -56,7 +56,7 @@ static void init_function_pointers(void)
GDI_GET_PROC(SetRelAbs);
}
static int CALLBACK emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
static int CALLBACK eto_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
const ENHMETARECORD *emr, int n_objs, LPARAM param)
{
static int n_record;
@ -234,7 +234,7 @@ static void test_ExtTextOut(void)
if(pSetRelAbs) pSetRelAbs(hdcDisplay, RELATIVE);
SetBkMode(hdcDisplay, OPAQUE);
ret = EnumEnhMetaFile(hdcDisplay, hMetafile, emf_enum_proc, dx, &rc);
ret = EnumEnhMetaFile(hdcDisplay, hMetafile, eto_emf_enum_proc, dx, &rc);
ok( ret, "EnumEnhMetaFile error %ld\n", GetLastError());
ok( GetTextAlign(hdcDisplay) == (TA_UPDATECP | TA_CENTER | TA_BASELINE | TA_RTLREADING),
@ -248,16 +248,122 @@ static void test_ExtTextOut(void)
ok(emr_processed, "EnumEnhMetaFile couldn't find EMR_EXTTEXTOUTA or EMR_EXTTEXTOUTW record\n");
ok(!EnumEnhMetaFile(hdcDisplay, hMetafile, emf_enum_proc, dx, NULL),
ok(!EnumEnhMetaFile(hdcDisplay, hMetafile, eto_emf_enum_proc, dx, NULL),
"A valid hdc has to require a valid rc\n");
ok(EnumEnhMetaFile(NULL, hMetafile, emf_enum_proc, dx, NULL),
ok(EnumEnhMetaFile(NULL, hMetafile, eto_emf_enum_proc, dx, NULL),
"A null hdc does not require a valid rc\n");
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 savedc_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
const ENHMETARECORD *emr, int n_objs, LPARAM param)
{
static int save_state;
static int restore_no;
switch (emr->iType)
{
case EMR_HEADER:
save_state = 0;
restore_no = 0;
break;
case EMR_SAVEDC:
save_state++;
break;
case EMR_RESTOREDC:
{
EMRRESTOREDC *restoredc = (EMRRESTOREDC *)emr;
switch(++restore_no)
{
case 1:
ok(restoredc->iRelative == -1, "first restore %ld\n", restoredc->iRelative);
break;
case 2:
ok(restoredc->iRelative == -3, "second restore %ld\n", restoredc->iRelative);
break;
case 3:
ok(restoredc->iRelative == -2, "third restore %ld\n", restoredc->iRelative);
break;
}
ok(restore_no <= 3, "restore_no %d\n", restore_no);
save_state += restoredc->iRelative;
break;
}
case EMR_EOF:
ok(save_state == 0, "EOF save_state %d\n", save_state);
break;
}
return 1;
}
void test_SaveDC(void)
{
HDC hdcMetafile, hdcDisplay;
HENHMETAFILE hMetafile;
HWND hwnd;
int ret;
static const RECT rc = { 0, 0, 100, 100 };
/* 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());
/* Need to write something to the emf, otherwise Windows won't play it back */
LineTo(hdcMetafile, 100, 100);
ret = SaveDC(hdcMetafile);
ok(ret == 1, "ret = %d\n", ret);
ret = SaveDC(hdcMetafile);
ok(ret == 2, "ret = %d\n", ret);
ret = SaveDC(hdcMetafile);
ok(ret == 3, "ret = %d\n", ret);
ret = RestoreDC(hdcMetafile, -1);
ok(ret, "ret = %d\n", ret);
ret = SaveDC(hdcMetafile);
ok(ret == 3, "ret = %d\n", ret);
ret = RestoreDC(hdcMetafile, 1);
ok(ret, "ret = %d\n", ret);
ret = SaveDC(hdcMetafile);
ok(ret == 1, "ret = %d\n", ret);
ret = SaveDC(hdcMetafile);
ok(ret == 2, "ret = %d\n", ret);
hMetafile = CloseEnhMetaFile(hdcMetafile);
ok(hMetafile != 0, "CloseEnhMetaFile error %ld\n", GetLastError());
ret = EnumEnhMetaFile(hdcDisplay, hMetafile, savedc_emf_enum_proc, 0, &rc);
ok( ret == 1, "EnumEnhMetaFile rets %d\n", ret);
ret = DeleteEnhMetaFile(hMetafile);
ok( ret, "DeleteEnhMetaFile error %ld\n", GetLastError());
ret = ReleaseDC(hwnd, hdcDisplay);
ok( ret, "ReleaseDC error %ld\n", GetLastError());
DestroyWindow(hwnd);
}
/* Win-format metafile (mfdrv) tests */
@ -813,6 +919,7 @@ START_TEST(metafile)
/* For enhanced metafiles (enhmfdrv) */
test_ExtTextOut();
test_SaveDC();
/* For win-format metafiles (mfdrv) */
test_mf_Blank();