summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Fl_Shared_Image.cxx233
1 files changed, 176 insertions, 57 deletions
diff --git a/src/Fl_Shared_Image.cxx b/src/Fl_Shared_Image.cxx
index 62c06079a..d3f76cce9 100644
--- a/src/Fl_Shared_Image.cxx
+++ b/src/Fl_Shared_Image.cxx
@@ -48,18 +48,26 @@ extern "C" {
}
-/** Returns the Fl_Shared_Image* array */
+/**
+ Returns the Fl_Shared_Image* array.
+
+ \return a pointer to an array of shared image pointers, sorted by name and size
+ \see Fl_Shared_Image::num_images()
+ */
Fl_Shared_Image **Fl_Shared_Image::images() {
return images_;
}
+/**
+ Number of shared images in their various cached sizes.
-/** Returns the total number of shared images in the array. */
+ \return number of entries in the array
+ \see Fl_Shared_Image::images()
+ */
int Fl_Shared_Image::num_images() {
return num_images_;
}
-
/**
Compares two shared images.
@@ -77,6 +85,7 @@ int Fl_Shared_Image::num_images() {
and the original_ flags set. This is not implemented via binary search, but
by a simple run of the array inside Fl_Shared_Image::find().
+ \param[in] i0, i1 image pointer pointer for sorting
\returns Whether the images match or their relative sort order (see text).
\retval 0 the images match
\retval <0 Image \p i0 is \e less than image \p i1
@@ -95,7 +104,6 @@ Fl_Shared_Image::compare(Fl_Shared_Image **i0, // I - First image
}
}
-
/**
Creates an empty shared image.
The constructors create a new shared image record in the image cache.
@@ -118,9 +126,12 @@ Fl_Shared_Image::Fl_Shared_Image() : Fl_Image(0,0,0) {
The constructors are protected and cannot be used directly
from a program. Use the get() method instead.
+
+ \param[in] n filename or pool name of the image, must be unique among shared images
+ \param[in] img the image that is made available using the name
*/
-Fl_Shared_Image::Fl_Shared_Image(const char *n, // I - Filename
- Fl_Image *img) // I - Image
+Fl_Shared_Image::Fl_Shared_Image(const char *n,
+ Fl_Image *img)
: Fl_Image(0,0,0) {
name_ = new char[strlen(n) + 1];
strcpy((char *)name_, n);
@@ -134,14 +145,15 @@ Fl_Shared_Image::Fl_Shared_Image(const char *n, // I - Filename
else update();
}
-
/**
- Adds a shared image to the image cache.
+ Adds a shared image to the image pool.
- This \b protected method adds an image to the cache, an ordered list
- of shared images. The cache is searched for a matching image whenever
+ This \b protected method adds an image to the pool, an ordered list
+ of shared images. The pool is searched for a matching image whenever
one is requested, for instance with Fl_Shared_Image::get() or
Fl_Shared_Image::find().
+
+ This method does not increase or decrease reference counts!
*/
void
Fl_Shared_Image::add() {
@@ -170,11 +182,11 @@ Fl_Shared_Image::add() {
}
}
+/**
+ Update the dimensions of the shared images.
-//
-// 'Fl_Shared_Image::update()' - Update the dimensions of the shared images.
-//
-
+ Internal method to synchronize shared image data with the actual image data.
+ */
void
Fl_Shared_Image::update() {
if (image_) {
@@ -199,7 +211,6 @@ Fl_Shared_Image::~Fl_Shared_Image() {
if (alloc_image_) delete image_;
}
-
/**
Releases and possibly destroys (if refcount <= 0) a shared image.
@@ -208,29 +219,39 @@ 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() %016x\n", this);
+ print_pool();
+#endif
+
+ if (refcount_ <= 0) return; // assert(refcount_>0);
refcount_ --;
if (refcount_ > 0) return;
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
+ the_original = o;
+ }
+ if (o) {
o->release(); // release from find() operation
}
}
- for (i = 0; i < num_images_; i ++)
+ for (i = 0; i < num_images_; i ++) {
if (images_[i] == this) {
num_images_ --;
if (i < num_images_) {
memmove(images_ + i, images_ + i + 1,
- (num_images_ - i) * sizeof(Fl_Shared_Image *));
+ (num_images_ - i) * sizeof(Fl_Shared_Image *));
}
break;
}
+ }
delete this;
@@ -238,11 +259,17 @@ void Fl_Shared_Image::release() {
delete[] images_;
images_ = 0;
- alloc_images_ = 0;
+ alloc_images_ = NULL;
}
+#ifdef SHIM_DEBUG
+ printf("<---- Fl_Shared_Image::release() %016x\n", this);
+ print_pool();
+ printf("\n");
+#endif
+ if (the_original)
+ the_original->release(); // release as a reference to this copy of the image
}
-
/** Reloads the shared image from disk. */
void Fl_Shared_Image::reload() {
// Load image from disk...
@@ -290,15 +317,19 @@ void Fl_Shared_Image::reload() {
}
}
-
-//
-// 'Fl_Shared_Image::copy()' - Copy and resize a shared image...
-//
-// Note: intentionally no doxygen docs here.
-// For doxygen docs see Fl_Image::copy().
-
-Fl_Image *
-Fl_Shared_Image::copy(int W, int H) const {
+/**
+ Create a resized copy of the image and wrap it into the share image class.
+
+ This function is usually followed by a call to `returned_image->add() to add
+ the image to the pool, and `this->refcounter_++` to make sure that the original
+ shared image keeps a reference to the copy. Don't call this function if
+ an image of the given size is already in the pool.
+
+ \param[in] W, H new image size
+ \return a new shared image pointer that is not yet in the pool
+ */
+Fl_Shared_Image *
+Fl_Shared_Image::copy_(int W, int H) const {
Fl_Image *temp_image; // New image file
Fl_Shared_Image *temp_shared; // New shared image
@@ -321,25 +352,80 @@ Fl_Shared_Image::copy(int W, int H) const {
return temp_shared;
}
+/**
+ Return a shared image of this image with the requested size.
+
+ This is the same as calling `Fl_Shared_Image::get(this->name(), W, H)`.
+
+ If a shared image of the desired size already exists in the shared image
+ pool, the existing image is returned and no copy is made. But the reference
+ counter is incremented. When the image is no longer used, call
+ `Fl_Shared_Image::release()`.
+
+ To get a copy of the image data, call `this->image()->copy(W, H)` instead.
+
+ \param[in] W, H size of requested image
+ \return pointer to an `Fl_Shared_Image` that can be safely cast, or NULL if
+ the image can't be found and can't be created.
+ */
+Fl_Image *Fl_Shared_Image::copy(int W, int H) const {
+ if (name_) // should always be set
+ return Fl_Shared_Image::get(name_, W, H);
+ else
+ return NULL;
+}
-//
-// 'Fl_Shared_Image::color_average()' - Blend colors...
-//
+/**
+ Increments the reference counter and returns a pointer to itself.
+
+ When the image is no longer used, call `Fl_Shared_Image::release()`.
+
+ To get a copy of the image data, call `this->image()->copy()` instead.
+
+ \return pointer to an `Fl_Shared_Image` that can be safely cast
+ */
+Fl_Image *Fl_Shared_Image::copy() {
+ refcount_++;
+ return this;
+}
+
+Fl_Image *Fl_Shared_Image::copy() const {
+ if (name_) // should always be set
+ return Fl_Shared_Image::get(name_);
+ else
+ return NULL;
+}
+/**
+ Averages the colors in the image with the provided FLTK color value.
+
+ This method changes the pixel data of this specific image.
+
+ \note It does not change any of the resized copies of this image, nor does it
+ necessarily apply the color changes if this image is resized later.
+
+ \param[in] c blend with this color
+ \param[in] bland fraction
+ \see Fl_Image::color_average(Fl_Color c, float i)
+ */
void
-Fl_Shared_Image::color_average(Fl_Color c, // I - Color to blend with
- float i) { // I - Blend fraction
+Fl_Shared_Image::color_average(Fl_Color c, float i) {
if (!image_) return;
image_->color_average(c, i);
update();
}
+/**
+ Convert the image to gray scale.
-//
-// 'Fl_Shared_Image::desaturate()' - Convert the image to grayscale...
-//
+ This method changes the pixel data of this specific image.
+
+ \note It does not change any of the resized copies of this image, nor does it
+ necessarily apply the color changes if this image is resized later.
+ \see Fl_Image::desaturate()
+ */
void
Fl_Shared_Image::desaturate() {
if (!image_) return;
@@ -348,9 +434,12 @@ Fl_Shared_Image::desaturate() {
update();
}
-//
-// 'Fl_Shared_Image::draw()' - Draw a shared image...
-//
+/**
+ Draw this image to the current graphics context.
+
+ \param[in] X, Y, W, H draw at this position and size
+ \param[in] cx, cy image origin
+ */
void Fl_Shared_Image::draw(int X, int Y, int W, int H, int cx, int cy) {
if (!image_) {
Fl_Image::draw(X, Y, W, H, cx, cy);
@@ -363,20 +452,16 @@ void Fl_Shared_Image::draw(int X, int Y, int W, int H, int cx, int cy) {
image_->scale(width, height, 0, 1);
}
+/**
+ Remove the cached device specific image data.
-
-
-//
-// 'Fl_Shared_Image::uncache()' - Uncache the shared image...
-//
-
+ \see Fl_Image::uncache()
+ */
void Fl_Shared_Image::uncache()
{
if (image_) image_->uncache();
}
-
-
/** Finds a shared image from its name and size specifications.
This uses a binary search in the image cache.
@@ -451,7 +536,6 @@ Fl_Shared_Image* Fl_Shared_Image::find(const char *name, int W, int H) {
return NULL;
}
-
/**
Find or load an image that can be shared by multiple widgets.
@@ -481,6 +565,8 @@ Fl_Shared_Image* Fl_Shared_Image::find(const char *name, int W, int H) {
\param name name of the image
\param W, H desired size
+ \return the image at the requested size, or NULL if the image could not be
+ found or generated
\see Fl_Shared_Image::find(const char *name, int W, int H)
\see Fl_Shared_Image::release()
@@ -488,26 +574,42 @@ Fl_Shared_Image* Fl_Shared_Image::find(const char *name, int W, int H) {
\see Fl_PNG_Image::Fl_PNG_Image (const char *name_png, const unsigned char *buffer, int maxsize)
*/
Fl_Shared_Image* Fl_Shared_Image::get(const char *name, int W, int H) {
- Fl_Shared_Image *temp; // Image
+ Fl_Shared_Image *temp;
+ 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 = 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;
@@ -529,7 +631,6 @@ Fl_Shared_Image *Fl_Shared_Image::get(Fl_RGB_Image *rgb, int own_it)
return shared;
}
-
/** Adds a shared image handler, which is basically a test function
for adding new image formats.
@@ -572,7 +673,6 @@ void Fl_Shared_Image::add_handler(Fl_Shared_Handler f) {
num_handlers_ ++;
}
-
/** Removes a shared image handler. */
void Fl_Shared_Image::remove_handler(Fl_Shared_Handler f) {
int i; // Looping var...
@@ -593,3 +693,22 @@ void Fl_Shared_Image::remove_handler(Fl_Shared_Handler f) {
(num_handlers_ - i) * sizeof(Fl_Shared_Handler ));
}
}
+
+#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; i<num_images_; i++) {
+ Fl_Shared_Image *img = images_[i];
+ printf("%3d: %3d(%c) %4dx%4d: %s\n",
+ i,
+ img->refcount_,
+ img->original_ ? 'O' : '_',
+ img->w(), img->h(),
+ img->name()
+ );
+ }
+}
+#endif