#include <stdio.h>
#include <stdlib.h>
#include <FL/fl_utf8.h>
#include "flstring.h"
#include <FL/Fl.H>
#include <FL/Fl_Shared_Image.H>
#include <FL/Fl_XBM_Image.H>
#include <FL/Fl_XPM_Image.H>
#include <FL/Fl_Preferences.H>
#include <FL/fl_draw.H>
Fl_Shared_Image **Fl_Shared_Image::images_ = 0; int Fl_Shared_Image::num_images_ = 0; int Fl_Shared_Image::alloc_images_ = 0;
Fl_Shared_Handler *Fl_Shared_Image::handlers_ = 0;int Fl_Shared_Image::num_handlers_ = 0; int Fl_Shared_Image::alloc_handlers_ = 0;
extern "C" {
typedef int (*compare_func_t)(const void *, const void *);
}
Fl_Shared_Image **Fl_Shared_Image::images() {
return images_;
}
int Fl_Shared_Image::num_images() {
return num_images_;
}
int
Fl_Shared_Image::compare(Fl_Shared_Image **i0, Fl_Shared_Image **i1) { int i = strcmp((*i0)->name(), (*i1)->name());
if (i) {
return i;
} else if ((*i0)->data_w() != (*i1)->data_w()) {
return (*i0)->data_w() - (*i1)->data_w();
} else {
return (*i0)->data_h() - (*i1)->data_h();
}
}
Fl_Shared_Image::Fl_Shared_Image() : Fl_Image(0,0,0) {
name_ = 0;
refcount_ = 1;
original_ = 0;
image_ = 0;
alloc_image_ = 0;
}
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);
refcount_ = 1;
image_ = img;
alloc_image_ = !img;
original_ = 1;
if (!img) reload();
else update();
}
void
Fl_Shared_Image::add() {
Fl_Shared_Image **temp;
if (num_images_ >= alloc_images_) {
temp = new Fl_Shared_Image *[alloc_images_ + 32];
if (alloc_images_) {
memcpy(temp, images_, alloc_images_ * sizeof(Fl_Shared_Image *));
delete[] images_;
}
images_ = temp;
alloc_images_ += 32;
}
images_[num_images_] = this;
num_images_ ++;
if (num_images_ > 1) {
qsort(images_, num_images_, sizeof(Fl_Shared_Image *),
(compare_func_t)compare);
}
}
void
Fl_Shared_Image::update() {
if (image_) {
int W = w(), H = h();
w(image_->data_w());
h(image_->data_h());
d(image_->d());
data(image_->data(), image_->count());
if (W && H) scale(W, H, 0, 1);
}
}
Fl_Shared_Image::~Fl_Shared_Image() {
if (name_) delete[] (char *)name_;
if (alloc_image_) delete image_;
}
void Fl_Shared_Image::release() {
int i; 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; refcount_ --;
if (refcount_ > 0) return;
if (!original()) {
Fl_Shared_Image *o = find(name());
if (o) {
if (o->original() && o!=this && o->refcount_>1)
the_original = o; o->release(); }
}
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 *));
}
break;
}
}
delete this;
if (num_images_ == 0 && images_) {
delete[] images_;
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
if (the_original)
the_original->release();
}
void Fl_Shared_Image::reload() {
int i; int count = 0; FILE *fp; uchar header[64]; Fl_Image *img;
if (!name_) return;
if ((fp = fl_fopen(name_, "rb")) != NULL) {
count = (int)fread(header, 1, sizeof(header), fp);
fclose(fp);
if (count == 0)
return;
} else {
return;
}
if (count >= 7 && memcmp(header, "#define", 7) == 0) img = new Fl_XBM_Image(name_);
else if (count >= 9 && memcmp(header, "/* XPM */", 9) == 0) img = new Fl_XPM_Image(name_);
else {
for (i = 0, img = 0; i < num_handlers_; i ++) {
img = (handlers_[i])(name_, header, count);
if (img) break;
}
}
if (img) {
if (alloc_image_) delete image_;
alloc_image_ = 1;
image_ = img;
int W = w();
int H = h();
update();
if (W)
scale(W, H, 0, 1);
}
}
Fl_Shared_Image *
Fl_Shared_Image::copy_(int W, int H) const {
Fl_Image *temp_image; Fl_Shared_Image *temp_shared;
if (!image_) temp_image = 0;
else temp_image = image_->copy(W, H);
temp_shared = new Fl_Shared_Image();
temp_shared->name_ = new char[strlen(name_) + 1];
strcpy((char *)temp_shared->name_, name_);
temp_shared->refcount_ = 1;
temp_shared->image_ = temp_image;
temp_shared->alloc_image_ = 1;
temp_shared->update();
return temp_shared;
}
Fl_Image *Fl_Shared_Image::copy(int W, int H) const {
if (name_) return Fl_Shared_Image::get(name_, W, H);
else
return NULL;
}
Fl_Image *Fl_Shared_Image::copy() {
refcount_++;
return this;
}
Fl_Image *Fl_Shared_Image::copy() const {
if (name_) return Fl_Shared_Image::get(name_);
else
return NULL;
}
void
Fl_Shared_Image::color_average(Fl_Color c, float i) {
if (!image_) return;
image_->color_average(c, i);
update();
}
void
Fl_Shared_Image::desaturate() {
if (!image_) return;
image_->desaturate();
update();
}
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);
return;
}
int width = image_->w(), height = image_->h();
image_->scale(w(), h(), 0, 1);
image_->draw(X, Y, W, H, cx, cy);
image_->scale(width, height, 0, 1);
}
void Fl_Shared_Image::uncache()
{
if (image_) image_->uncache();
}
Fl_Shared_Image* Fl_Shared_Image::find(const char *name, int W, int H) {
if (num_images_) {
if (W) {
Fl_Shared_Image *key; Fl_Shared_Image **match;
key = new Fl_Shared_Image();
key->name_ = new char[strlen(name) + 1];
strcpy((char *)key->name_, name);
key->w(W);
key->h(H);
match = (Fl_Shared_Image **)bsearch(&key, images_, num_images_,
sizeof(Fl_Shared_Image *),
(compare_func_t)compare);
delete key;
if (match) {
(*match)->refcount_ ++;
return *match;
}
} else {
int i;
for (i = 0; i < num_images_; ++i) {
Fl_Shared_Image *img = images_[i];
if (img->original_ && img->name_ && (strcmp(img->name_, name) == 0)) {
img->refcount_++;
return img;
}
}
}
}
return NULL;
}
Fl_Shared_Image* Fl_Shared_Image::get(const char *name, int W, int H) {
Fl_Shared_Image *temp;
bool temp_referenced = false;
if ((temp = find(name, W, H)) != NULL)
return temp;
temp = find(name);
if (temp) {
temp_referenced = true;
} else {
temp = new Fl_Shared_Image(name);
if (!temp->image_) {
delete temp;
return NULL;
}
temp->add();
}
if ((temp->w() != W || temp->h() != H) && W && H) {
Fl_Shared_Image *new_temp = temp->copy_(W, H);
if (!new_temp) return NULL;
if (!temp_referenced)
temp->refcount_++;
new_temp->add();
return new_temp;
}
return temp;
}
Fl_Shared_Image *Fl_Shared_Image::get(Fl_RGB_Image *rgb, int own_it)
{
Fl_Shared_Image *shared = new Fl_Shared_Image(Fl_Preferences::newUUID(), rgb);
shared->alloc_image_ = own_it;
shared->add();
return shared;
}
void Fl_Shared_Image::add_handler(Fl_Shared_Handler f) {
int i; Fl_Shared_Handler *temp;
for (i = 0; i < num_handlers_; i ++) {
if (handlers_[i] == f) return;
}
if (num_handlers_ >= alloc_handlers_) {
temp = new Fl_Shared_Handler [alloc_handlers_ + 32];
if (alloc_handlers_) {
memcpy(temp, handlers_, alloc_handlers_ * sizeof(Fl_Shared_Handler));
delete[] handlers_;
}
handlers_ = temp;
alloc_handlers_ += 32;
}
handlers_[num_handlers_] = f;
num_handlers_ ++;
}
void Fl_Shared_Image::remove_handler(Fl_Shared_Handler f) {
int i;
for (i = 0; i < num_handlers_; i ++) {
if (handlers_[i] == f) break;
}
if (i >= num_handlers_) return;
num_handlers_ --;
if (i < num_handlers_) {
memmove(handlers_ + i, handlers_ + i + 1,
(num_handlers_ - i) * sizeof(Fl_Shared_Handler ));
}
}
#ifdef SHIM_DEBUG
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