emfs: handle deletion (yet again:)

Huw D M Davies h.davies1 at physics.ox.ac.uk
Mon Nov 24 17:42:17 CST 2003


Hopefully I've now convinced Alexandre to commit this, so here is it
before he changes his mind <g>

        Huw Davies <huw at codeweavers.com>
        Lets 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.

Index: include/gdi.h
===================================================================
RCS file: /home/wine/wine/include/gdi.h,v
retrieving revision 1.86
diff -u -r1.86 gdi.h
--- include/gdi.h	5 Nov 2003 01:43:57 -0000	1.86
+++ include/gdi.h	24 Nov 2003 23:35:52 -0000
@@ -64,12 +64,19 @@
     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 @@
     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);
@@ -470,6 +478,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 */
 
Index: objects/gdiobj.c
===================================================================
RCS file: /home/wine/wine/objects/gdiobj.c,v
retrieving revision 1.91
diff -u -r1.91 gdiobj.c
--- objects/gdiobj.c	5 Nov 2003 01:43:57 -0000	1.91
+++ objects/gdiobj.c	24 Nov 2003 23:35:53 -0000
@@ -717,6 +717,7 @@
     obj->wMagic  = magic|OBJECT_NOSYSTEM;
     obj->dwCount = 0;
     obj->funcs   = funcs;
+    obj->hdcs    = NULL;
 
     TRACE_SEC( *handle, "enter" );
     return obj;
@@ -890,6 +891,24 @@
 	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 +928,78 @@
     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.@)
Index: dlls/gdi/enhmfdrv/enhmetafiledrv.h
===================================================================
RCS file: /home/wine/wine/dlls/gdi/enhmfdrv/enhmetafiledrv.h,v
retrieving revision 1.14
diff -u -r1.14 enhmetafiledrv.h
--- dlls/gdi/enhmfdrv/enhmetafiledrv.h	10 Oct 2003 00:06:59 -0000	1.14
+++ dlls/gdi/enhmfdrv/enhmetafiledrv.h	24 Nov 2003 23:35:53 -0000
@@ -35,7 +35,8 @@
     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 @@
 
 
 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 @@
                               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.27
diff -u -r1.27 init.c
--- dlls/gdi/enhmfdrv/init.c	5 Nov 2003 01:43:57 -0000	1.27
+++ dlls/gdi/enhmfdrv/init.c	24 Nov 2003 23:35:53 -0000
@@ -47,6 +47,7 @@
     NULL,                            /* pCreateDIBSection */
     NULL,                            /* pDeleteBitmap */
     NULL,                            /* pDeleteDC */
+    EMFDRV_DeleteObject,             /* pDeleteObject */
     NULL,                            /* pDescribePixelFormat */
     NULL,                            /* pDeviceCapabilities */
     EMFDRV_Ellipse,                  /* pEllipse */
@@ -159,8 +160,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->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 @@
     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 @@
         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);
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	24 Nov 2003 23:35:53 -0000
@@ -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 @@
 	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 @@
 	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 @@
  */
 HBRUSH EMFDRV_SelectBrush(PHYSDEV dev, HBRUSH hBrush )
 {
+    EMFDRV_PDEVICE *physDev = (EMFDRV_PDEVICE*)dev;
     EMRSELECTOBJECT emr;
     DWORD index;
     int i;
@@ -130,7 +199,11 @@
             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 @@
 
     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 @@
  */
 HFONT EMFDRV_SelectFont( PHYSDEV dev, HFONT hFont )
 {
+    EMFDRV_PDEVICE *physDev = (EMFDRV_PDEVICE*)dev;
     EMRSELECTOBJECT emr;
     DWORD index;
     int i;
@@ -203,7 +277,13 @@
             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 @@
 
     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 @@
  */
 HPEN EMFDRV_SelectPen(PHYSDEV dev, HPEN hPen )
 {
+    EMFDRV_PDEVICE *physDev = (EMFDRV_PDEVICE*)dev;
     EMRSELECTOBJECT emr;
     DWORD index;
     int i;
@@ -257,7 +338,12 @@
             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);
Index: dlls/gdi/mfdrv/init.c
===================================================================
RCS file: /home/wine/wine/dlls/gdi/mfdrv/init.c,v
retrieving revision 1.26
diff -u -r1.26 init.c
--- dlls/gdi/mfdrv/init.c	5 Nov 2003 01:43:57 -0000	1.26
+++ dlls/gdi/mfdrv/init.c	24 Nov 2003 23:35:53 -0000
@@ -48,6 +48,7 @@
     NULL,                            /* pCreateDIBSection */
     NULL,                            /* pDeleteBitmap */
     NULL,                            /* pDeleteDC */
+    NULL,                            /* pDeleteObject */
     NULL,                            /* pDescribePixelFormat */
     NULL,                            /* pDeviceCapabilities */
     MFDRV_Ellipse,                   /* pEllipse */



More information about the wine-patches mailing list