gdi32: Handle metafiles directly in SelectObject.

Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Huw Davies <huw@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Jacek Caban 2021-08-09 11:30:32 +02:00 committed by Alexandre Julliard
parent 3f95a13595
commit 5fdfe8c2d0
8 changed files with 219 additions and 37 deletions

View File

@ -147,7 +147,7 @@ DC *alloc_dc_ptr( WORD magic )
HeapFree( GetProcessHeap(), 0, dc );
return NULL;
}
dc->nulldrv.hdc = dc->hSelf;
dc->attr->hdc = dc->nulldrv.hdc = dc->hSelf;
set_gdi_client_ptr( dc->hSelf, dc->attr );
if (!font_driver.pCreateDC( &dc->physDev, NULL, NULL, NULL, NULL ))

View File

@ -83,6 +83,7 @@ extern BOOL METADC_ScaleViewportExtEx( HDC hdc, INT x_num, INT x_denom, INT y_nu
INT y_denom ) DECLSPEC_HIDDEN;
extern BOOL METADC_ScaleWindowExtEx( HDC hdc, INT x_num, INT x_denom, INT y_num,
INT y_denom ) DECLSPEC_HIDDEN;
extern HGDIOBJ METADC_SelectObject( HDC hdc, HGDIOBJ obj ) DECLSPEC_HIDDEN;
extern BOOL METADC_SetBkMode( HDC hdc, INT mode ) DECLSPEC_HIDDEN;
extern BOOL METADC_SetLayout( HDC hdc, DWORD layout ) DECLSPEC_HIDDEN;
extern BOOL METADC_SetTextCharacterExtra( HDC hdc, INT extra ) DECLSPEC_HIDDEN;

View File

@ -179,12 +179,12 @@ static const struct gdi_dc_funcs MFDRV_Funcs =
NULL, /* pResetDC */
MFDRV_RestoreDC, /* pRestoreDC */
NULL, /* pRoundRect */
MFDRV_SelectBitmap, /* pSelectBitmap */
MFDRV_SelectBrush, /* pSelectBrush */
NULL, /* pSelectBitmap */
NULL, /* pSelectBrush */
MFDRV_SelectClipPath, /* pSelectClipPath */
MFDRV_SelectFont, /* pSelectFont */
NULL, /* pSelectFont */
MFDRV_SelectPalette, /* pSelectPalette */
MFDRV_SelectPen, /* pSelectPen */
NULL, /* pSelectPen */
MFDRV_SetBkColor, /* pSetBkColor */
MFDRV_SetBoundsRect, /* pSetBoundsRect */
MFDRV_SetDCBrushColor, /* pSetDCBrushColor*/
@ -313,6 +313,9 @@ HDC WINAPI CreateMetaFileW( LPCWSTR filename )
if (!(dc = MFDRV_AllocMetaFile())) return 0;
physDev = (METAFILEDRV_PDEVICE *)dc->physDev;
physDev->mh->mtType = METAFILE_MEMORY;
physDev->pen = GetStockObject( BLACK_PEN );
physDev->brush = GetStockObject( WHITE_BRUSH );
physDev->font = GetStockObject( DEVICE_DEFAULT_FONT );
if (filename) /* disk based metafile */
{

View File

@ -38,6 +38,9 @@ typedef struct
UINT handles_size, cur_handles;
HGDIOBJ *handles;
HANDLE hFile; /* Handle for disk based MetaFile */
HPEN pen;
HBRUSH brush;
HFONT font;
} METAFILEDRV_PDEVICE;
#define HANDLE_LIST_INC 20
@ -91,11 +94,7 @@ extern BOOL CDECL MFDRV_PolyBezier( PHYSDEV dev, const POINT* pt, DWORD count )
extern BOOL CDECL MFDRV_PolyBezierTo( PHYSDEV dev, const POINT* pt, DWORD count ) DECLSPEC_HIDDEN;
extern BOOL CDECL MFDRV_RestoreDC( PHYSDEV dev, INT level ) DECLSPEC_HIDDEN;
extern BOOL CDECL MFDRV_ScaleWindowExtEx( PHYSDEV dev, INT xNum, INT xDenom, INT yNum, INT yDenom, SIZE *size ) DECLSPEC_HIDDEN;
extern HBITMAP CDECL MFDRV_SelectBitmap( PHYSDEV dev, HBITMAP handle ) DECLSPEC_HIDDEN;
extern HBRUSH CDECL MFDRV_SelectBrush( PHYSDEV dev, HBRUSH hbrush, const struct brush_pattern *pattern ) DECLSPEC_HIDDEN;
extern BOOL CDECL MFDRV_SelectClipPath( PHYSDEV dev, INT iMode ) DECLSPEC_HIDDEN;
extern HFONT CDECL MFDRV_SelectFont( PHYSDEV dev, HFONT handle, UINT *aa_flags ) DECLSPEC_HIDDEN;
extern HPEN CDECL MFDRV_SelectPen( PHYSDEV dev, HPEN handle, const struct brush_pattern *pattern ) DECLSPEC_HIDDEN;
extern HPALETTE CDECL MFDRV_SelectPalette( PHYSDEV dev, HPALETTE hPalette, BOOL bForceBackground) DECLSPEC_HIDDEN;
extern UINT CDECL MFDRV_RealizePalette(PHYSDEV dev, HPALETTE hPalette, BOOL primary) DECLSPEC_HIDDEN;
extern COLORREF CDECL MFDRV_SetBkColor( PHYSDEV dev, COLORREF color ) DECLSPEC_HIDDEN;

View File

@ -102,7 +102,7 @@ void METADC_DeleteObject( HDC hdc, HGDIOBJ obj )
INT16 index;
if ((index = MFDRV_FindObject( &metadc->dev, obj )) < 0) return;
if (obj == GetCurrentObject( hdc, GetObjectType( obj )))
if (obj == metadc->pen || obj == metadc->brush || obj == metadc->font)
{
WARN( "deleting selected object %p\n", obj );
return;
@ -134,14 +134,6 @@ static BOOL MFDRV_SelectObject( PHYSDEV dev, INT16 index)
}
/***********************************************************************
* MFDRV_SelectBitmap
*/
HBITMAP CDECL MFDRV_SelectBitmap( PHYSDEV dev, HBITMAP hbitmap )
{
return 0;
}
/******************************************************************
* MFDRV_CreateBrushIndirect
*/
@ -227,21 +219,26 @@ done:
/***********************************************************************
* MFDRV_SelectBrush
* METADC_SelectBrush
*/
HBRUSH CDECL MFDRV_SelectBrush( PHYSDEV dev, HBRUSH hbrush, const struct brush_pattern *pattern )
static HBRUSH METADC_SelectBrush( HDC hdc, HBRUSH hbrush )
{
METAFILEDRV_PDEVICE *metadc = get_metadc_ptr( hdc );
INT16 index;
HBRUSH ret;
index = MFDRV_FindObject(dev, hbrush);
index = MFDRV_FindObject( &metadc->dev, hbrush );
if( index < 0 )
{
index = MFDRV_CreateBrushIndirect( dev, hbrush );
index = MFDRV_CreateBrushIndirect( &metadc->dev, hbrush );
if( index < 0 )
return 0;
GDI_hdc_using_object( hbrush, dev->hdc, METADC_DeleteObject );
GDI_hdc_using_object( hbrush, hdc, METADC_DeleteObject );
}
return MFDRV_SelectObject( dev, index ) ? hbrush : 0;
if (!MFDRV_SelectObject( &metadc->dev, index )) return 0;
ret = metadc->brush;
metadc->brush = hbrush;
return ret;
}
/******************************************************************
@ -283,25 +280,29 @@ static UINT16 MFDRV_CreateFontIndirect(PHYSDEV dev, HFONT hFont, LOGFONTW *logfo
/***********************************************************************
* MFDRV_SelectFont
* METADC_SelectFont
*/
HFONT CDECL MFDRV_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
static HFONT METADC_SelectFont( HDC hdc, HFONT hfont )
{
METAFILEDRV_PDEVICE *metadc = get_metadc_ptr( hdc );
LOGFONTW font;
INT16 index;
HFONT ret;
*aa_flags = GGO_BITMAP; /* no point in anti-aliasing on metafiles */
index = MFDRV_FindObject(dev, hfont);
index = MFDRV_FindObject( &metadc->dev, hfont );
if( index < 0 )
{
if (!GetObjectW( hfont, sizeof(font), &font ))
return 0;
index = MFDRV_CreateFontIndirect(dev, hfont, &font);
index = MFDRV_CreateFontIndirect( &metadc->dev, hfont, &font );
if( index < 0 )
return 0;
GDI_hdc_using_object( hfont, dev->hdc, METADC_DeleteObject );
GDI_hdc_using_object( hfont, hdc, METADC_DeleteObject );
}
return MFDRV_SelectObject( dev, index ) ? hfont : 0;
if (!MFDRV_SelectObject( &metadc->dev, index )) return 0;
ret = metadc->font;
metadc->font = hfont;
return ret;
}
/******************************************************************
@ -322,14 +323,16 @@ static UINT16 MFDRV_CreatePenIndirect(PHYSDEV dev, HPEN hPen, LOGPEN16 *logpen)
/***********************************************************************
* MFDRV_SelectPen
* METADC_SelectPen
*/
HPEN CDECL MFDRV_SelectPen( PHYSDEV dev, HPEN hpen, const struct brush_pattern *pattern )
static HPEN METADC_SelectPen( HDC hdc, HPEN hpen )
{
METAFILEDRV_PDEVICE *metadc = get_metadc_ptr( hdc );
LOGPEN16 logpen;
INT16 index;
HPEN ret;
index = MFDRV_FindObject(dev, hpen);
index = MFDRV_FindObject( &metadc->dev, hpen );
if( index < 0 )
{
/* must be an extended pen */
@ -361,12 +364,16 @@ HPEN CDECL MFDRV_SelectPen( PHYSDEV dev, HPEN hpen, const struct brush_pattern *
HeapFree( GetProcessHeap(), 0, elp );
}
index = MFDRV_CreatePenIndirect( dev, hpen, &logpen );
index = MFDRV_CreatePenIndirect( &metadc->dev, hpen, &logpen );
if( index < 0 )
return 0;
GDI_hdc_using_object( hpen, dev->hdc, METADC_DeleteObject );
GDI_hdc_using_object( hpen, hdc, METADC_DeleteObject );
}
return MFDRV_SelectObject( dev, index ) ? hpen : 0;
if (!MFDRV_SelectObject( &metadc->dev, index )) return 0;
ret = metadc->pen;
metadc->pen = hpen;
return ret;
}
@ -459,3 +466,21 @@ UINT CDECL MFDRV_RealizePalette(PHYSDEV dev, HPALETTE hPalette, BOOL dummy)
use in the case of metafiles, we'll always return 1. */
return 1;
}
HGDIOBJ METADC_SelectObject( HDC hdc, HGDIOBJ obj )
{
switch (gdi_handle_type( obj ))
{
case NTGDI_OBJ_BRUSH:
return METADC_SelectBrush( hdc, obj );
case NTGDI_OBJ_FONT:
return METADC_SelectFont( hdc, obj );
case NTGDI_OBJ_PEN:
case NTGDI_OBJ_EXTPEN:
return METADC_SelectPen( hdc, obj );
default:
SetLastError( ERROR_INVALID_FUNCTION );
return 0;
}
}

View File

@ -274,6 +274,8 @@ HGDIOBJ WINAPI SelectObject( HDC hdc, HGDIOBJ obj )
TRACE( "(%p,%p)\n", hdc, obj );
if (is_meta_dc( hdc )) return METADC_SelectObject( hdc, obj );
switch (get_object_type( obj ))
{
case NTGDI_OBJ_PEN:

View File

@ -3628,6 +3628,156 @@ static void test_mf_DCBrush(void)
ok(ret, "DeleteMetaFile(%p) error %d\n", hMetafile, GetLastError());
}
static void test_mf_select(void)
{
HMETAFILE hmf;
HDC hdc, hdc2;
HGDIOBJ obj;
HPEN pen;
int cnt;
BOOL ret;
static const unsigned char select_bits[] =
{
0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x4d, 0x00,
0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00,
0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xfc, 0x02,
0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x2d, 0x01, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0xfc, 0x02, 0x00, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x04, 0x00,
0x00, 0x00, 0x2d, 0x01, 0x01, 0x00, 0x08, 0x00,
0x00, 0x00, 0xfa, 0x02, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x04, 0x00,
0x00, 0x00, 0x2d, 0x01, 0x02, 0x00, 0x03, 0x00,
0x00, 0x00, 0x1e, 0x00, 0x08, 0x00, 0x00, 0x00,
0xfa, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x2d, 0x01, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00,
0x27, 0x01, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00,
0x2d, 0x01, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00,
0xf0, 0x01, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00,
0x27, 0x01, 0xfb, 0xff, 0x03, 0x00, 0x00, 0x00,
0x00, 0x00
};
static const unsigned char delete_not_selected_bits[] =
{
0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x28, 0x00,
0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00,
0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xfa, 0x02,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01,
0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x2d, 0x01,
0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xfa, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x2d, 0x01,
0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0xf0, 0x01,
0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00
};
static const unsigned char delete_selected_bits[] =
{
0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x18, 0x00,
0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00,
0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xfa, 0x02,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01,
0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x2d, 0x01,
0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00
};
hdc = CreateMetaFileA(NULL);
ok(hdc != 0, "CreateMetaFileA failed\n");
obj = SelectObject(hdc, GetStockObject(DC_BRUSH));
ok(obj == GetStockObject(WHITE_BRUSH), "brush is not a stock WHITE_BRUSH: %p\n", obj);
obj = SelectObject(hdc, GetStockObject(WHITE_BRUSH));
ok(obj == GetStockObject(DC_BRUSH), "brush is not a stock DC_BRUSH: %p\n", obj);
pen = CreatePen(PS_SOLID, 1, RGB(1,1,1));
obj = SelectObject(hdc, pen);
ok(obj == GetStockObject(BLACK_PEN), "pen is not a stock BLACK_PEN: %p\n", obj);
cnt = SaveDC(hdc);
ok(cnt == 1, "cnt = %d\n", cnt);
obj = SelectObject(hdc, GetStockObject(BLACK_PEN));
ok(obj == pen, "unexpected pen: %p\n", obj);
ret = RestoreDC(hdc, -1);
ok(ret, "RestoreDC failed\n");
obj = SelectObject(hdc, GetStockObject(BLACK_PEN));
/* pen is still black after RestoreDC */
ok(obj == GetStockObject(BLACK_PEN), "unexpected pen: %p\n", obj);
ret = DeleteObject(pen);
ok(ret, "DeleteObject failed: %u\n", GetLastError());
obj = GetCurrentObject(hdc, OBJ_PEN);
todo_wine
ok(!obj, "GetCurrentObject succeeded\n");
SetLastError(0xdeadbeef);
obj = SelectObject(hdc, GetStockObject(DEFAULT_PALETTE));
ok(!obj && GetLastError() == ERROR_INVALID_FUNCTION,
"SelectObject returned %p (%u).\n", obj, GetLastError());
ret = RestoreDC(hdc, -5);
ok(ret, "RestoreDC failed\n");
hmf = CloseMetaFile(hdc);
ok(hmf != 0, "CloseMetaFile failed\n");
if (compare_mf_bits(hmf, select_bits, sizeof(select_bits), "mf_select"))
{
dump_mf_bits(hmf, "mf_select");
EnumMetaFile(0, hmf, mf_enum_proc, 0);
}
ret = DeleteMetaFile(hmf);
ok(ret, "DeleteMetaFile(%p) error %d\n", hmf, GetLastError());
/* create two metafiles, select the same pen to both of them,
* unselect it from only one and then delete */
hdc = CreateMetaFileA(NULL);
ok(hdc != 0, "CreateMetaFileA failed\n");
hdc2 = CreateMetaFileA(NULL);
ok(hdc2 != 0, "CreateMetaFileA failed\n");
pen = CreatePen(PS_SOLID, 1, RGB(1,1,1));
obj = SelectObject(hdc, pen);
ok(obj == GetStockObject(BLACK_PEN), "pen is not a stock BLACK_PEN: %p\n", obj);
obj = SelectObject(hdc2, pen);
ok(obj == GetStockObject(BLACK_PEN), "pen is not a stock BLACK_PEN: %p\n", obj);
obj = SelectObject(hdc, GetStockObject(BLACK_PEN));
ok(obj == pen, "unexpected pen: %p\n", obj);
ret = DeleteObject(pen);
ok(ret, "DeleteObject failed: %u\n", GetLastError());
hmf = CloseMetaFile(hdc);
ok(hmf != 0, "CloseMetaFile failed\n");
if (compare_mf_bits(hmf, delete_not_selected_bits,
sizeof(delete_not_selected_bits), "mf_delete_not_selected"))
{
dump_mf_bits(hmf, "mf_delete_not_selected");
EnumMetaFile(0, hmf, mf_enum_proc, 0);
}
ret = DeleteMetaFile(hmf);
ok(ret, "DeleteMetaFile(%p) error %d\n", hmf, GetLastError());
hmf = CloseMetaFile(hdc2);
ok(hmf != 0, "CloseMetaFile failed\n");
if (compare_mf_bits(hmf, delete_selected_bits,
sizeof(delete_selected_bits), "mf_delete_selected"))
{
dump_mf_bits(hmf, "mf_delete_selected");
EnumMetaFile(0, hmf, mf_enum_proc, 0);
}
ret = DeleteMetaFile(hmf);
ok(ret, "DeleteMetaFile(%p) error %d\n", hmf, GetLastError());
}
static void test_mf_ExtTextOut_on_path(void)
{
HDC hdcMetafile;
@ -6453,6 +6603,7 @@ START_TEST(metafile)
test_mf_SetPixel();
test_mf_FloodFill();
test_mf_attrs();
test_mf_select();
/* For metafile conversions */
test_mf_conversions();

View File

@ -110,6 +110,7 @@ enum
typedef struct DC_ATTR
{
HDC hdc; /* handle to self */
LONG disabled; /* disabled flag, controled by DCHF_(DISABLE|ENABLE)DC */
COLORREF background_color;
COLORREF brush_color;