Hi,
This patch attempts to conserve handles when generating enhanced metafiles. It was originally written by Huw Davies, however I have modified it to not use extra space in the GDI heap, as per Alexandre's objections.
The same thing needs to be done for old format metafiles too, but I'll wait until this patch is accepted first.
Mike
ChangeLog: <huw@codeweavers.com> <mike@codeweavers.com> * elimate duplication of handles when generating EMFs
Index: dlls/gdi/enhmfdrv/enhmetafiledrv.h =================================================================== RCS file: /home/wine/wine/dlls/gdi/enhmfdrv/enhmetafiledrv.h,v retrieving revision 1.11 diff -u -r1.11 enhmetafiledrv.h --- dlls/gdi/enhmfdrv/enhmetafiledrv.h 23 Jun 2003 19:46:56 -0000 1.11 +++ dlls/gdi/enhmfdrv/enhmetafiledrv.h 27 Jul 2003 08:12:38 -0000 @@ -27,12 +27,20 @@ /* Enhanced Metafile driver physical DC */ +typedef struct _EMFDRV_handle_info +{ + DWORD type; + DWORD size; + BYTE data[1]; +} EMFDRV_handle_info; + typedef struct { HDC hdc; DC *dc; ENHMETAHEADER *emh; /* Pointer to enhanced metafile header */ - UINT nextHandle; /* Next handle number */ + UINT handles_size, cur_handles; + EMFDRV_handle_info **handle_info; HANDLE hFile; /* Handle for disk based MetaFile */ INT horzres, vertres; INT horzsize, vertsize; @@ -46,10 +54,11 @@ 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, @@ -63,6 +72,7 @@ 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 ); Index: dlls/gdi/enhmfdrv/init.c =================================================================== RCS file: /home/wine/wine/dlls/gdi/enhmfdrv/init.c,v retrieving revision 1.19 diff -u -r1.19 init.c --- dlls/gdi/enhmfdrv/init.c 23 Jun 2003 19:46:56 -0000 1.19 +++ dlls/gdi/enhmfdrv/init.c 27 Jul 2003 08:12:39 -0000 @@ -154,8 +154,13 @@ { 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->handle_info[index] ) + HeapFree( GetProcessHeap(), 0, physDev->handle_info[index] ); + HeapFree( GetProcessHeap(), 0, physDev->handle_info ); HeapFree( GetProcessHeap(), 0, physDev ); dc->physDev = NULL; GDI_FreeObject( dc->hSelf, dc ); @@ -212,20 +217,6 @@ 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.@) @@ -312,7 +303,10 @@ return 0; } - physDev->nextHandle = 1; + physDev->handle_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + HANDLE_LIST_INC * sizeof(physDev->handle_info[0])); + physDev->handles_size = HANDLE_LIST_INC; + physDev->cur_handles = 1; physDev->hFile = 0; physDev->horzres = GetDeviceCaps(hRefDC, HORZRES); Index: dlls/gdi/enhmfdrv/objects.c =================================================================== RCS file: /home/wine/wine/dlls/gdi/enhmfdrv/objects.c,v retrieving revision 1.7 diff -u -r1.7 objects.c --- dlls/gdi/enhmfdrv/objects.c 21 May 2003 18:28:49 -0000 1.7 +++ dlls/gdi/enhmfdrv/objects.c 27 Jul 2003 08:12:39 -0000 @@ -28,6 +28,127 @@ WINE_DEFAULT_DEBUG_CHANNEL(enhmetafile); + +/****************************************************************** + * EMFDRV_AddHandle + */ +static UINT EMFDRV_AddHandle( PHYSDEV dev, HGDIOBJ obj ) +{ + EMFDRV_PDEVICE *physDev = (EMFDRV_PDEVICE *)dev; + UINT index, type, size; + EMFDRV_handle_info *info; + + type = GetObjectType( obj ); + if( !type ) + return 0; + size = GetObjectW( obj, 0, NULL ); + if( !size ) + return 0; + + for(index = 0; index < physDev->handles_size; index++) + if(physDev->handle_info[index] == NULL) break; + if(index == physDev->handles_size) + { + UINT len = physDev->handles_size + HANDLE_LIST_INC; + EMFDRV_handle_info **temp = physDev->handle_info; + + temp = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + temp, len * sizeof temp[0]); + if( !temp ) + return 0; + physDev->handle_info = temp; + physDev->handles_size = len; + } + + info = HeapAlloc( GetProcessHeap(), 0, + sizeof (EMFDRV_handle_info) + size ); + if( !info ) + return 0; + + info->type = type; + info->size = size; + if( size != GetObjectW( obj, size, info->data )) + return 0; + + physDev->handle_info[index] = info; + + 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, type, size; + EMFDRV_handle_info *info, *x; + + type = GetObjectType( obj ); + if( !type ) + return 0; + size = GetObjectW( obj, 0, NULL ); + if( !size ) + return 0; + + for(index = 0; index < physDev->handles_size; index++) + { + x = physDev->handle_info[index]; + if( !x ) + continue; + if( type != x->type ) + continue; + if( size != x->size ) + continue; + info = HeapAlloc( GetProcessHeap(), 0, size ); + if( info ) + { + BOOL ok = TRUE; + + if( ok && ( size != GetObjectW( obj, size, info ) ) ) + ok = FALSE; + if( ok && memcmp( info, x->data, size ) ) + ok = FALSE; + + HeapFree( GetProcessHeap(), 0, info ); + if( ok ) + break; + } + } + + if(index == physDev->handles_size) return 0; + + return index + 1; +} + + +/****************************************************************** + * EMFDRV_DeleteObject + */ +BOOL EMFDRV_DeleteObject( PHYSDEV dev, HGDIOBJ obj ) +{ + EMRDELETEOBJECT emr; + 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; + + return ret; +} + + /*********************************************************************** * EMFDRV_SelectBitmap */ @@ -55,7 +176,7 @@ 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 +201,7 @@ 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; @@ -130,6 +251,9 @@ goto found; } } + if((index = EMFDRV_FindObject(dev, hBrush)) != 0) + goto found; + if (!(index = EMFDRV_CreateBrushIndirect(dev, hBrush ))) return 0; found: @@ -153,7 +277,7 @@ 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; @@ -203,7 +327,12 @@ goto found; } } + + if((index = EMFDRV_FindObject(dev, hFont)) != 0) + goto found; + if (!(index = EMFDRV_CreateFontIndirect(dev, hFont ))) return HGDI_ERROR; + found: emr.emr.iType = EMR_SELECTOBJECT; emr.emr.nSize = sizeof(emr); @@ -227,7 +356,7 @@ 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; @@ -257,7 +386,11 @@ goto found; } } + if((index = EMFDRV_FindObject(dev, hPen)) != 0) + goto found; + if (!(index = (DWORD)EMFDRV_CreatePenIndirect(dev, hPen ))) return 0; + found: emr.emr.iType = EMR_SELECTOBJECT; emr.emr.nSize = sizeof(emr);