From b2dc8217a17f0e89b303461743965f2b3699a570 Mon Sep 17 00:00:00 2001 From: Matthias Melcher Date: Sun, 14 Jan 2024 16:56:01 +0100 Subject: [PATCH] #877: Fixes Fl_Shared_IMage refcount --- FL/Fl_Shared_Image.H | 5 +++ src/Fl_Shared_Image.cxx | 69 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 66 insertions(+), 8 deletions(-) diff --git a/FL/Fl_Shared_Image.H b/FL/Fl_Shared_Image.H index d32e74703..0601fefe2 100644 --- a/FL/Fl_Shared_Image.H +++ b/FL/Fl_Shared_Image.H @@ -24,6 +24,7 @@ # include "Fl_Image.H" +#undef SHIM_DEBUG // Test function for adding new formats typedef Fl_Image *(*Fl_Shared_Handler)(const char *name, uchar *header, @@ -82,6 +83,10 @@ protected: void update(); public: +#ifdef SHIM_DEBUG + static void print_pool(); +#endif + /** Returns the filename of the shared image */ const char *name() { return name_; } diff --git a/src/Fl_Shared_Image.cxx b/src/Fl_Shared_Image.cxx index 276392e07..5f9706aa1 100644 --- a/src/Fl_Shared_Image.cxx +++ b/src/Fl_Shared_Image.cxx @@ -3,7 +3,7 @@ // // Shared image code for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2023 by Bill Spitzak and others. +// Copyright 1998-2024 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -217,14 +217,24 @@ Fl_Shared_Image::~Fl_Shared_Image() { */ void Fl_Shared_Image::release() { int i; // Looping var... + Fl_Shared_Image *the_original = NULL; +#ifdef SHIM_DEBUG + printf("----> Fl_Shared_Image::release() %d %s %d %d\n", original_, name_, w(), h()); + print_pool(); +#endif + + if (refcount_ <= 0) return; // assert(refcount_>0); refcount_ --; if (refcount_ > 0) return; + // If this image is not the original, find the original image and make sure + // to delete its reference counter as well at the end of this method. if (!original()) { Fl_Shared_Image *o = find(name()); - if (o && o->original() && o!=this) { - o->release(); // release as a reference to this copy of the image + if (o) { + if (o->original() && o!=this && o->refcount_>1) + the_original = o; // mark to release later o->release(); // release from find() operation } } @@ -249,6 +259,15 @@ void Fl_Shared_Image::release() { images_ = 0; alloc_images_ = 0; } +#ifdef SHIM_DEBUG + printf("<---- Fl_Shared_Image::release() %d %s %d %d\n", original_, name_, w(), h()); + print_pool(); + printf("\n"); +#endif + + // Release one reference count in the original image as well. + if (the_original) + the_original->release(); } @@ -579,25 +598,41 @@ Fl_Shared_Image* Fl_Shared_Image::find(const char *name, int W, int H) { */ Fl_Shared_Image* Fl_Shared_Image::get(const char *name, int W, int H) { Fl_Shared_Image *temp; // Image + bool temp_referenced = false; + // Find an image by the requested size // ::find() increments the ref count for us if ((temp = find(name, W, H)) != NULL) return temp; - if ((temp = find(name)) == NULL) { + // Find the original image, size does not matter + temp = find(name); + if (temp) { + temp_referenced = true; + } else { + // No original found, so we generate it by loading the file temp = new Fl_Shared_Image(name); - + // We can't load the file or create the image, so return fail if (!temp->image_) { delete temp; return NULL; } - + // Add the new image to the pool, refcount is already at 1 temp->add(); } + // At this point, temp is an original image + // But if the size is wrong, generate a resized copy if ((temp->w() != W || temp->h() != H) && W && H) { - temp = (Fl_Shared_Image *)temp->copy(W, H); - temp->add(); + // Generate a copy with the new size, the copy gets refcount 1 + Fl_Shared_Image *new_temp = (Fl_Shared_Image *)temp->copy(W, H); + if (!new_temp) return NULL; + // Also increment the refcount of the original image + if (!temp_referenced) + temp->refcount_++; + // add the newly created image to the pool and return it + new_temp->add(); + return new_temp; } return temp; @@ -672,6 +707,24 @@ void Fl_Shared_Image::remove_handler(Fl_Shared_Handler f) { } } +#ifdef SHIM_DEBUG +/** + Print the contents of the shared image pool. + */ +void Fl_Shared_Image::print_pool() { + printf("Fl_Shared_Image: %d images stored in a pool of %d\n", num_images_, alloc_images_); + for (int i=0; irefcount_, + img->original_ ? 'O' : '_', + img->w(), img->h(), + img->name() + ); + } +} +#endif // // End of "$Id$".