From 9e8ce63e2efc35f745d7865b28815a715b766d18 Mon Sep 17 00:00:00 2001 From: Huw Davies Date: Tue, 25 Nov 2003 05:03:09 +0000 Subject: [PATCH] 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. --- dlls/gdi/enhmfdrv/enhmetafiledrv.h | 7 ++- dlls/gdi/enhmfdrv/init.c | 25 +++----- dlls/gdi/enhmfdrv/objects.c | 94 ++++++++++++++++++++++++++++-- dlls/gdi/mfdrv/init.c | 1 + include/gdi.h | 11 ++++ objects/gdiobj.c | 90 ++++++++++++++++++++++++++++ 6 files changed, 206 insertions(+), 22 deletions(-) diff --git a/dlls/gdi/enhmfdrv/enhmetafiledrv.h b/dlls/gdi/enhmfdrv/enhmetafiledrv.h index f01ce3185a8..bfac9c6307a 100644 --- a/dlls/gdi/enhmfdrv/enhmetafiledrv.h +++ b/dlls/gdi/enhmfdrv/enhmetafiledrv.h @@ -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 ); diff --git a/dlls/gdi/enhmfdrv/init.c b/dlls/gdi/enhmfdrv/init.c index af727f662c9..e22df0ff61d 100644 --- a/dlls/gdi/enhmfdrv/init.c +++ b/dlls/gdi/enhmfdrv/init.c @@ -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); diff --git a/dlls/gdi/enhmfdrv/objects.c b/dlls/gdi/enhmfdrv/objects.c index b72340b2e2c..b5b388b76c4 100644 --- a/dlls/gdi/enhmfdrv/objects.c +++ b/dlls/gdi/enhmfdrv/objects.c @@ -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); diff --git a/dlls/gdi/mfdrv/init.c b/dlls/gdi/mfdrv/init.c index 2a0afbb1b83..75e0e647fa7 100644 --- a/dlls/gdi/mfdrv/init.c +++ b/dlls/gdi/mfdrv/init.c @@ -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 */ diff --git a/include/gdi.h b/include/gdi.h index ac900f3df98..76b90d80296 100644 --- a/include/gdi.h +++ b/include/gdi.h @@ -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 */ diff --git a/objects/gdiobj.c b/objects/gdiobj.c index e1f92f2530f..70b6929e475 100644 --- a/objects/gdiobj.c +++ b/objects/gdiobj.c @@ -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.@)