Commit 9e8ce63e authored by Huw Davies's avatar Huw Davies Committed by Alexandre Julliard

Let enhmetafiles reuse gdi handles. This works by a dc 'registering'

with an object that it wants to know when the object is deleted. Until the dc gets delete notification it's free to assume that it doesn't need to write the create record for that object again. Upon receiving the delete notification it writes the DeleteObject record. Windows seems to do it this way too.
parent 6281d82e
......@@ -35,7 +35,8 @@ typedef struct
HDC hdc;
DC *dc;
ENHMETAHEADER *emh; /* Pointer to enhanced metafile header */
UINT nextHandle; /* Next handle number */
UINT handles_size, cur_handles;
HGDIOBJ *handles;
HANDLE hFile; /* Handle for disk based MetaFile */
INT horzres, vertres;
INT horzsize, vertsize;
......@@ -49,10 +50,11 @@ typedef struct
extern BOOL EMFDRV_WriteRecord( PHYSDEV dev, EMR *emr );
extern int EMFDRV_AddHandleDC( PHYSDEV dev );
extern void EMFDRV_UpdateBBox( PHYSDEV dev, RECTL *rect );
extern DWORD EMFDRV_CreateBrushIndirect( PHYSDEV dev, HBRUSH hBrush );
#define HANDLE_LIST_INC 20
/* Metafile driver functions */
extern BOOL EMFDRV_AbortPath( PHYSDEV dev );
extern BOOL EMFDRV_Arc( PHYSDEV dev, INT left, INT top, INT right,
......@@ -66,6 +68,7 @@ extern BOOL EMFDRV_Chord( PHYSDEV dev, INT left, INT top, INT right,
INT bottom, INT xstart, INT ystart, INT xend,
INT yend );
extern BOOL EMFDRV_CloseFigure( PHYSDEV dev );
extern BOOL EMFDRV_DeleteObject( PHYSDEV dev, HGDIOBJ obj );
extern BOOL EMFDRV_Ellipse( PHYSDEV dev, INT left, INT top,
INT right, INT bottom );
extern BOOL EMFDRV_EndPath( PHYSDEV dev );
......
......@@ -47,6 +47,7 @@ static const DC_FUNCTIONS EMFDRV_Funcs =
NULL, /* pCreateDIBSection */
NULL, /* pDeleteBitmap */
NULL, /* pDeleteDC */
EMFDRV_DeleteObject, /* pDeleteObject */
NULL, /* pDescribePixelFormat */
NULL, /* pDeviceCapabilities */
EMFDRV_Ellipse, /* pEllipse */
......@@ -159,8 +160,13 @@ static BOOL EMFDRV_DeleteDC( PHYSDEV dev )
{
EMFDRV_PDEVICE *physDev = (EMFDRV_PDEVICE *)dev;
DC *dc = physDev->dc;
UINT index;
if (physDev->emh) HeapFree( GetProcessHeap(), 0, physDev->emh );
for(index = 0; index < physDev->handles_size; index++)
if(physDev->handles[index])
GDI_hdc_not_using_object(physDev->handles[index], physDev->hdc);
HeapFree( GetProcessHeap(), 0, physDev->handles );
HeapFree( GetProcessHeap(), 0, physDev );
dc->physDev = NULL;
GDI_FreeObject( dc->hSelf, dc );
......@@ -224,21 +230,6 @@ void EMFDRV_UpdateBBox( PHYSDEV dev, RECTL *rect )
return;
}
/******************************************************************
* EMFDRV_AddHandleDC
*
* Note: this function assumes that we never delete objects.
* If we do someday, we'll need to maintain a table to re-use deleted
* handles.
*/
int EMFDRV_AddHandleDC( PHYSDEV dev )
{
EMFDRV_PDEVICE *physDev = (EMFDRV_PDEVICE *)dev;
physDev->emh->nHandles++;
return physDev->nextHandle++;
}
/**********************************************************************
* CreateEnhMetaFileA (GDI32.@)
*/
......@@ -324,7 +315,9 @@ HDC WINAPI CreateEnhMetaFileW(
return 0;
}
physDev->nextHandle = 1;
physDev->handles = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, HANDLE_LIST_INC * sizeof(physDev->handles[0]));
physDev->handles_size = HANDLE_LIST_INC;
physDev->cur_handles = 1;
physDev->hFile = 0;
physDev->horzres = GetDeviceCaps(hRefDC, HORZRES);
......
......@@ -28,6 +28,74 @@
WINE_DEFAULT_DEBUG_CHANNEL(enhmetafile);
/******************************************************************
* EMFDRV_AddHandle
*/
static UINT EMFDRV_AddHandle( PHYSDEV dev, HGDIOBJ obj )
{
EMFDRV_PDEVICE *physDev = (EMFDRV_PDEVICE *)dev;
UINT index;
for(index = 0; index < physDev->handles_size; index++)
if(physDev->handles[index] == 0) break;
if(index == physDev->handles_size) {
physDev->handles_size += HANDLE_LIST_INC;
physDev->handles = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
physDev->handles,
physDev->handles_size * sizeof(physDev->handles[0]));
}
physDev->handles[index] = obj;
physDev->cur_handles++;
if(physDev->cur_handles > physDev->emh->nHandles)
physDev->emh->nHandles++;
return index + 1; /* index 0 is reserved for the hmf, so we increment everything by 1 */
}
/******************************************************************
* EMFDRV_FindObject
*/
static UINT EMFDRV_FindObject( PHYSDEV dev, HGDIOBJ obj )
{
EMFDRV_PDEVICE *physDev = (EMFDRV_PDEVICE*) dev;
UINT index;
for(index = 0; index < physDev->handles_size; index++)
if(physDev->handles[index] == obj) break;
if(index == physDev->handles_size) return 0;
return index + 1;
}
/******************************************************************
* EMFDRV_DeleteObject
*/
BOOL EMFDRV_DeleteObject( PHYSDEV dev, HGDIOBJ obj )
{
EMRDELETEOBJECT emr;
EMFDRV_PDEVICE *physDev = (EMFDRV_PDEVICE*) dev;
UINT index;
BOOL ret = TRUE;
if(!(index = EMFDRV_FindObject(dev, obj))) return 0;
emr.emr.iType = EMR_DELETEOBJECT;
emr.emr.nSize = sizeof(emr);
emr.ihObject = index;
if(!EMFDRV_WriteRecord( dev, &emr.emr ))
ret = FALSE;
physDev->handles[index - 1] = 0;
physDev->cur_handles--;
return ret;
}
/***********************************************************************
* EMFDRV_SelectBitmap
*/
......@@ -55,7 +123,7 @@ DWORD EMFDRV_CreateBrushIndirect( PHYSDEV dev, HBRUSH hBrush )
EMRCREATEBRUSHINDIRECT emr;
emr.emr.iType = EMR_CREATEBRUSHINDIRECT;
emr.emr.nSize = sizeof(emr);
emr.ihBrush = index = EMFDRV_AddHandleDC( dev );
emr.ihBrush = index = EMFDRV_AddHandle( dev, hBrush );
emr.lb = logbrush;
if(!EMFDRV_WriteRecord( dev, &emr.emr ))
......@@ -80,7 +148,7 @@ DWORD EMFDRV_CreateBrushIndirect( PHYSDEV dev, HBRUSH hBrush )
if(!emr) break;
emr->emr.iType = EMR_CREATEDIBPATTERNBRUSHPT;
emr->emr.nSize = size;
emr->ihBrush = index = EMFDRV_AddHandleDC( dev );
emr->ihBrush = index = EMFDRV_AddHandle( dev, hBrush );
emr->iUsage = LOWORD(logbrush.lbColor);
emr->offBmi = sizeof(EMRCREATEDIBPATTERNBRUSHPT);
emr->cbBmi = biSize;
......@@ -113,6 +181,7 @@ DWORD EMFDRV_CreateBrushIndirect( PHYSDEV dev, HBRUSH hBrush )
*/
HBRUSH EMFDRV_SelectBrush(PHYSDEV dev, HBRUSH hBrush )
{
EMFDRV_PDEVICE *physDev = (EMFDRV_PDEVICE*)dev;
EMRSELECTOBJECT emr;
DWORD index;
int i;
......@@ -130,7 +199,11 @@ HBRUSH EMFDRV_SelectBrush(PHYSDEV dev, HBRUSH hBrush )
goto found;
}
}
if((index = EMFDRV_FindObject(dev, hBrush)) != 0)
goto found;
if (!(index = EMFDRV_CreateBrushIndirect(dev, hBrush ))) return 0;
GDI_hdc_using_object(hBrush, physDev->hdc);
found:
emr.emr.iType = EMR_SELECTOBJECT;
......@@ -153,7 +226,7 @@ static BOOL EMFDRV_CreateFontIndirect(PHYSDEV dev, HFONT hFont )
emr.emr.iType = EMR_EXTCREATEFONTINDIRECTW;
emr.emr.nSize = (sizeof(emr) + 3) / 4 * 4;
emr.ihFont = index = EMFDRV_AddHandleDC( dev );
emr.ihFont = index = EMFDRV_AddHandle( dev, hFont );
emr.elfw.elfFullName[0] = '\0';
emr.elfw.elfStyle[0] = '\0';
emr.elfw.elfVersion = 0;
......@@ -185,6 +258,7 @@ static BOOL EMFDRV_CreateFontIndirect(PHYSDEV dev, HFONT hFont )
*/
HFONT EMFDRV_SelectFont( PHYSDEV dev, HFONT hFont )
{
EMFDRV_PDEVICE *physDev = (EMFDRV_PDEVICE*)dev;
EMRSELECTOBJECT emr;
DWORD index;
int i;
......@@ -203,7 +277,13 @@ HFONT EMFDRV_SelectFont( PHYSDEV dev, HFONT hFont )
goto found;
}
}
if((index = EMFDRV_FindObject(dev, hFont)) != 0)
goto found;
if (!(index = EMFDRV_CreateFontIndirect(dev, hFont ))) return HGDI_ERROR;
GDI_hdc_using_object(hFont, physDev->hdc);
found:
emr.emr.iType = EMR_SELECTOBJECT;
emr.emr.nSize = sizeof(emr);
......@@ -227,7 +307,7 @@ static HPEN EMFDRV_CreatePenIndirect(PHYSDEV dev, HPEN hPen )
emr.emr.iType = EMR_CREATEPEN;
emr.emr.nSize = sizeof(emr);
emr.ihPen = index = EMFDRV_AddHandleDC( dev );
emr.ihPen = index = EMFDRV_AddHandle( dev, hPen );
if(!EMFDRV_WriteRecord( dev, &emr.emr ))
index = 0;
......@@ -239,6 +319,7 @@ static HPEN EMFDRV_CreatePenIndirect(PHYSDEV dev, HPEN hPen )
*/
HPEN EMFDRV_SelectPen(PHYSDEV dev, HPEN hPen )
{
EMFDRV_PDEVICE *physDev = (EMFDRV_PDEVICE*)dev;
EMRSELECTOBJECT emr;
DWORD index;
int i;
......@@ -257,7 +338,12 @@ HPEN EMFDRV_SelectPen(PHYSDEV dev, HPEN hPen )
goto found;
}
}
if((index = EMFDRV_FindObject(dev, hPen)) != 0)
goto found;
if (!(index = (DWORD)EMFDRV_CreatePenIndirect(dev, hPen ))) return 0;
GDI_hdc_using_object(hPen, physDev->hdc);
found:
emr.emr.iType = EMR_SELECTOBJECT;
emr.emr.nSize = sizeof(emr);
......
......@@ -48,6 +48,7 @@ static const DC_FUNCTIONS MFDRV_Funcs =
NULL, /* pCreateDIBSection */
NULL, /* pDeleteBitmap */
NULL, /* pDeleteDC */
NULL, /* pDeleteObject */
NULL, /* pDescribePixelFormat */
NULL, /* pDeviceCapabilities */
MFDRV_Ellipse, /* pEllipse */
......
......@@ -64,12 +64,19 @@ struct gdi_obj_funcs
BOOL (*pDeleteObject)( HGDIOBJ handle, void *obj );
};
struct hdc_list
{
HDC hdc;
struct hdc_list *next;
};
typedef struct tagGDIOBJHDR
{
HANDLE16 hNext;
WORD wMagic;
DWORD dwCount;
const struct gdi_obj_funcs *funcs;
struct hdc_list *hdcs;
} GDIOBJHDR;
......@@ -189,6 +196,7 @@ typedef struct tagDC_FUNCS
HBITMAP (*pCreateDIBSection)(PHYSDEV,BITMAPINFO *,UINT,LPVOID *,HANDLE,DWORD,DWORD);
BOOL (*pDeleteBitmap)(HBITMAP);
BOOL (*pDeleteDC)(PHYSDEV);
BOOL (*pDeleteObject)(PHYSDEV,HGDIOBJ);
INT (*pDescribePixelFormat)(PHYSDEV,INT,UINT,PIXELFORMATDESCRIPTOR *);
DWORD (*pDeviceCapabilities)(LPSTR,LPCSTR,LPCSTR,WORD,LPSTR,LPDEVMODEA);
BOOL (*pEllipse)(PHYSDEV,INT,INT,INT,INT);
......@@ -471,6 +479,9 @@ extern DC * DC_GetDCUpdate( HDC hdc );
extern void DC_InitDC( DC * dc );
extern void DC_UpdateXforms( DC * dc );
BOOL GDI_hdc_using_object(HGDIOBJ obj, HDC hdc);
BOOL GDI_hdc_not_using_object(HGDIOBJ obj, HDC hdc);
/* bidi.c */
/* Wine_GCPW Flags */
......
......@@ -717,6 +717,7 @@ void *GDI_AllocObject( WORD size, WORD magic, HGDIOBJ *handle, const struct gdi_
obj->wMagic = magic|OBJECT_NOSYSTEM;
obj->dwCount = 0;
obj->funcs = funcs;
obj->hdcs = NULL;
TRACE_SEC( *handle, "enter" );
return obj;
......@@ -890,6 +891,23 @@ BOOL WINAPI DeleteObject( HGDIOBJ obj )
return TRUE;
}
while (header->hdcs)
{
DC *dc = DC_GetDCPtr(header->hdcs->hdc);
struct hdc_list *tmp;
TRACE("hdc %p has interest in %p\n", header->hdcs->hdc, obj);
if(dc)
{
if(dc->funcs->pDeleteObject)
dc->funcs->pDeleteObject( dc->physDev, obj );
GDI_ReleaseObj( header->hdcs->hdc );
}
tmp = header->hdcs;
header->hdcs = header->hdcs->next;
HeapFree(GetProcessHeap(), 0, tmp);
}
if (header->dwCount)
{
TRACE("delayed for %p because object in use, count %ld\n", obj, header->dwCount );
......@@ -909,6 +927,78 @@ BOOL WINAPI DeleteObject( HGDIOBJ obj )
return FALSE;
}
/***********************************************************************
* GDI_hdc_using_object
*
* Call this if the dc requires DeleteObject notification
*/
BOOL GDI_hdc_using_object(HGDIOBJ obj, HDC hdc)
{
GDIOBJHDR * header;
struct hdc_list **pphdc;
TRACE("obj %p hdc %p\n", obj, hdc);
if (!(header = GDI_GetObjPtr( obj, MAGIC_DONTCARE ))) return FALSE;
if (!(header->wMagic & OBJECT_NOSYSTEM) &&
(header->wMagic >= FIRST_MAGIC) && (header->wMagic <= LAST_MAGIC))
{
GDI_ReleaseObj(obj);
return FALSE;
}
for(pphdc = &header->hdcs; *pphdc; pphdc = &(*pphdc)->next)
if((*pphdc)->hdc == hdc)
break;
if(!*pphdc) {
*pphdc = HeapAlloc(GetProcessHeap(), 0, sizeof(**pphdc));
(*pphdc)->hdc = hdc;
(*pphdc)->next = NULL;
}
GDI_ReleaseObj(obj);
return TRUE;
}
/***********************************************************************
* GDI_hdc_not_using_object
*
*/
BOOL GDI_hdc_not_using_object(HGDIOBJ obj, HDC hdc)
{
GDIOBJHDR * header;
struct hdc_list *phdc, **prev;
TRACE("obj %p hdc %p\n", obj, hdc);
if (!(header = GDI_GetObjPtr( obj, MAGIC_DONTCARE ))) return FALSE;
if (!(header->wMagic & OBJECT_NOSYSTEM) &&
(header->wMagic >= FIRST_MAGIC) && (header->wMagic <= LAST_MAGIC))
{
GDI_ReleaseObj(obj);
return FALSE;
}
phdc = header->hdcs;
prev = &header->hdcs;
while(phdc) {
if(phdc->hdc == hdc) {
*prev = phdc->next;
HeapFree(GetProcessHeap(), 0, phdc);
phdc = *prev;
} else {
prev = &phdc->next;
phdc = phdc->next;
}
}
GDI_ReleaseObj(obj);
return TRUE;
}
/***********************************************************************
* GetStockObject (GDI32.@)
......
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