Handle conserving patch

Mike McCormack mike at codeweavers.com
Sun Jul 27 03:29:45 CDT 2003


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 at codeweavers.com>
<mike at codeweavers.com>
* elimate duplication of handles when generating EMFs


-------------- next part --------------
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);


More information about the wine-patches mailing list