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:
parent
be29e3708b
commit
0d23ac479b
|
@ -504,8 +504,9 @@ INT WINAPI SaveDC( HDC hdc )
|
||||||
if(dc->funcs->pSaveDC)
|
if(dc->funcs->pSaveDC)
|
||||||
{
|
{
|
||||||
ret = dc->funcs->pSaveDC( dc->physDev );
|
ret = dc->funcs->pSaveDC( dc->physDev );
|
||||||
|
if(ret)
|
||||||
|
ret = ++dc->saveLevel;
|
||||||
GDI_ReleaseObj( hdc );
|
GDI_ReleaseObj( hdc );
|
||||||
/* FIXME: ret is just a success flag, we should return a proper value */
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -551,26 +552,24 @@ BOOL WINAPI RestoreDC( HDC hdc, INT level )
|
||||||
TRACE("%p %d\n", hdc, level );
|
TRACE("%p %d\n", hdc, level );
|
||||||
dc = DC_GetDCUpdate( hdc );
|
dc = DC_GetDCUpdate( hdc );
|
||||||
if(!dc) return FALSE;
|
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(abs(level) > dc->saveLevel || level == 0)
|
||||||
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))
|
|
||||||
{
|
{
|
||||||
GDI_ReleaseObj( hdc );
|
GDI_ReleaseObj( hdc );
|
||||||
return FALSE;
|
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;
|
success=TRUE;
|
||||||
while (dc->saveLevel >= level)
|
while (dc->saveLevel >= level)
|
||||||
{
|
{
|
||||||
|
|
|
@ -38,19 +38,15 @@ BOOL EMFDRV_RestoreDC( PHYSDEV dev, INT level )
|
||||||
|
|
||||||
emr.emr.iType = EMR_RESTOREDC;
|
emr.emr.iType = EMR_RESTOREDC;
|
||||||
emr.emr.nSize = sizeof(emr);
|
emr.emr.nSize = sizeof(emr);
|
||||||
emr.iRelative = -1;
|
|
||||||
if (level == -1)
|
if (level < 0)
|
||||||
return EMFDRV_WriteRecord( dev, &emr.emr );
|
emr.iRelative = level;
|
||||||
else if (level > 0 && level <= physDev->dc->saveLevel)
|
else
|
||||||
{
|
emr.iRelative = level - physDev->dc->saveLevel - 1;
|
||||||
while (level >= physDev->dc->saveLevel)
|
|
||||||
{
|
EMFDRV_WriteRecord( dev, &emr.emr );
|
||||||
EMFDRV_WriteRecord( dev, &emr.emr );
|
|
||||||
level--;
|
return TRUE;
|
||||||
}
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UINT EMFDRV_SetTextAlign( PHYSDEV dev, UINT align )
|
UINT EMFDRV_SetTextAlign( PHYSDEV dev, UINT align )
|
||||||
|
|
|
@ -422,6 +422,9 @@ HENHMETAFILE WINAPI CloseEnhMetaFile(HDC hdc) /* [in] metafile DC */
|
||||||
if (!(dc = (DC *) GDI_GetObjPtr( hdc, ENHMETAFILE_DC_MAGIC ))) return 0;
|
if (!(dc = (DC *) GDI_GetObjPtr( hdc, ENHMETAFILE_DC_MAGIC ))) return 0;
|
||||||
physDev = (EMFDRV_PDEVICE *)dc->physDev;
|
physDev = (EMFDRV_PDEVICE *)dc->physDev;
|
||||||
|
|
||||||
|
if(dc->saveLevel)
|
||||||
|
RestoreDC(hdc, 1);
|
||||||
|
|
||||||
emr.emr.iType = EMR_EOF;
|
emr.emr.iType = EMR_EOF;
|
||||||
emr.emr.nSize = sizeof(emr);
|
emr.emr.nSize = sizeof(emr);
|
||||||
emr.nPalEntries = 0;
|
emr.nPalEntries = 0;
|
||||||
|
|
|
@ -2,6 +2,7 @@ Makefile
|
||||||
bitmap.ok
|
bitmap.ok
|
||||||
brush.ok
|
brush.ok
|
||||||
clipping.ok
|
clipping.ok
|
||||||
|
dc.ok
|
||||||
gdiobj.ok
|
gdiobj.ok
|
||||||
generated.ok
|
generated.ok
|
||||||
mapping.ok
|
mapping.ok
|
||||||
|
|
|
@ -9,6 +9,7 @@ CTESTS = \
|
||||||
bitmap.c \
|
bitmap.c \
|
||||||
brush.c \
|
brush.c \
|
||||||
clipping.c \
|
clipping.c \
|
||||||
|
dc.c \
|
||||||
gdiobj.c \
|
gdiobj.c \
|
||||||
generated.c \
|
generated.c \
|
||||||
mapping.c \
|
mapping.c \
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
|
@ -56,7 +56,7 @@ static void init_function_pointers(void)
|
||||||
GDI_GET_PROC(SetRelAbs);
|
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)
|
const ENHMETARECORD *emr, int n_objs, LPARAM param)
|
||||||
{
|
{
|
||||||
static int n_record;
|
static int n_record;
|
||||||
|
@ -234,7 +234,7 @@ static void test_ExtTextOut(void)
|
||||||
if(pSetRelAbs) pSetRelAbs(hdcDisplay, RELATIVE);
|
if(pSetRelAbs) pSetRelAbs(hdcDisplay, RELATIVE);
|
||||||
SetBkMode(hdcDisplay, OPAQUE);
|
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( ret, "EnumEnhMetaFile error %ld\n", GetLastError());
|
||||||
|
|
||||||
ok( GetTextAlign(hdcDisplay) == (TA_UPDATECP | TA_CENTER | TA_BASELINE | TA_RTLREADING),
|
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(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");
|
"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");
|
"A null hdc does not require a valid rc\n");
|
||||||
|
|
||||||
ret = DeleteEnhMetaFile(hMetafile);
|
ret = DeleteEnhMetaFile(hMetafile);
|
||||||
ok( ret, "DeleteEnhMetaFile error %ld\n", GetLastError());
|
ok( ret, "DeleteEnhMetaFile error %ld\n", GetLastError());
|
||||||
ret = ReleaseDC(hwnd, hdcDisplay);
|
ret = ReleaseDC(hwnd, hdcDisplay);
|
||||||
ok( ret, "ReleaseDC error %ld\n", GetLastError());
|
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 */
|
/* Win-format metafile (mfdrv) tests */
|
||||||
|
@ -813,6 +919,7 @@ START_TEST(metafile)
|
||||||
|
|
||||||
/* For enhanced metafiles (enhmfdrv) */
|
/* For enhanced metafiles (enhmfdrv) */
|
||||||
test_ExtTextOut();
|
test_ExtTextOut();
|
||||||
|
test_SaveDC();
|
||||||
|
|
||||||
/* For win-format metafiles (mfdrv) */
|
/* For win-format metafiles (mfdrv) */
|
||||||
test_mf_Blank();
|
test_mf_Blank();
|
||||||
|
|
Loading…
Reference in New Issue