Skip to content

Commit

Permalink
Allow GpGraphics to take ownership of GpMetafile on dispose
Browse files Browse the repository at this point in the history
The Windows GDI+ allows the metafile instance to be disposed before the
graphics instance.

To support that, keep track in the GpGraphics of whether it is responsible for
freeing the GpMetafile.

If the graphics instance is deleted first, own_metafile is FALSE and nothing
happens.

If the metafile instance is disposed first, set own_metafile to TRUE and don't
dispose of the metafile. It will be disposed when the graphics instance is
deleted.

---

Also on Windows GDI+ creating more than one graphics instance for a metafile
instance throws an OutOfMemoryException, so do the same in GdipGetImageGraphicsContext
  • Loading branch information
lambdageek committed Oct 7, 2020
1 parent 9efff6a commit 1af55cd
Show file tree
Hide file tree
Showing 5 changed files with 29 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/graphics-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ typedef struct _Graphics {
float aa_offset_y;
/* metafile-specific stuff */
EmfType emf_type;
BOOL own_metafile; /* true when metafile is owned by the graphics instance */
GpMetafile *metafile;
cairo_surface_t *metasurface; /* bogus surface to satisfy some API calls */
/* common-stuff */
Expand Down
14 changes: 13 additions & 1 deletion src/graphics.c
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,11 @@ gdip_graphics_metafile_init (GpGraphics *graphics, GpMetafile *metafile)
graphics->metasurface = cairo_image_surface_create (CAIRO_FORMAT_A1, 1, 1);
graphics->ct = cairo_create (graphics->metasurface);
graphics->metafile = metafile;
graphics->own_metafile = FALSE;

g_assert (metafile->graphics == NULL);
/* Track the graphics instance in the metafile */
metafile->graphics = graphics;

gdip_graphics_common_init (graphics);
}
Expand Down Expand Up @@ -455,8 +460,15 @@ GdipDeleteGraphics (GpGraphics *graphics)

if (graphics->backend == GraphicsBackEndMetafile) {
/* if recording this is where we save the metafile (stream or file) */
if (graphics->metafile->recording)
if (graphics->metafile && graphics->metafile->recording)
gdip_metafile_stop_recording (graphics->metafile);
/* break the link to the metafile */
if (graphics->metafile)
graphics->metafile->graphics = NULL;
if (graphics->own_metafile)
gdip_metafile_dispose (graphics->metafile);
graphics->metafile = NULL;
graphics->own_metafile = FALSE;
cairo_surface_destroy (graphics->metasurface);
graphics->metasurface = NULL;
}
Expand Down
3 changes: 3 additions & 0 deletions src/image.c
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,9 @@ GdipGetImageGraphicsContext (GpImage *image, GpGraphics **graphics)
GpMetafile *mf = (GpMetafile*)image;
if (!mf->recording)
return OutOfMemory;
/* creating more than one graphics instance for a metafile is not supported */
if (mf->graphics)
return OutOfMemory;
*graphics = gdip_metafile_graphics_new (mf);
return *graphics ? Ok : OutOfMemory;
}
Expand Down
1 change: 1 addition & 0 deletions src/metafile-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ struct _Metafile {
BOOL recording; /* recording into memory (data), file (fp) or user stream (stream) */
FILE *fp;
void *stream;
GpGraphics *graphics; /* set if GdipGetImageGraphicsContext was called */
};

typedef struct {
Expand Down
11 changes: 11 additions & 0 deletions src/metafile.c
Original file line number Diff line number Diff line change
Expand Up @@ -918,6 +918,7 @@ gdip_metafile_create ()
mf->recording = FALSE;
mf->fp = NULL;
mf->stream = NULL;
mf->graphics = NULL;
}
return mf;
}
Expand Down Expand Up @@ -970,6 +971,13 @@ gdip_metafile_dispose (GpMetafile *metafile)
if (!metafile)
return InvalidParameter;

if (metafile->graphics) {
g_assert (!metafile->graphics->own_metafile);
g_assert (metafile->graphics->metafile == metafile);
/* Transfer responsiblity to the graphics instance that outlives this metafile instance */
metafile->graphics->own_metafile = TRUE;
return Ok;
}
/* TODO deal with "delete" flag */
metafile->length = 0;
if (metafile->data) {
Expand All @@ -980,6 +988,9 @@ gdip_metafile_dispose (GpMetafile *metafile)
if (metafile->recording)
gdip_metafile_stop_recording (metafile);

/* if there was a graphics instance, it should already be cleaned up */
g_assert (metafile->graphics == NULL);

GdipFree (metafile);
return Ok;
}
Expand Down

0 comments on commit 1af55cd

Please sign in to comment.