1 #include "common.h"
2
3 #include <ctype.h>
4 #include <errno.h>
5 #include <fcntl.h>
6 #include <string.h>
7 #include <time.h>
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #ifdef BUILD_X11
11 #include <X11/Xlib.h>
12 #endif
13
14 #include "Imlib2.h"
15 #include "file.h"
16 #include "image.h"
17 #include "loaders.h"
18
19 /* Imlib loader context */
20 struct _imlibldctx {
21 ImlibProgressFunction progress;
22 char granularity;
23 int pct, area, row;
24 int pass, n_pass;
25 };
26
27 static ImlibImage *images = NULL;
28
29 #ifdef BUILD_X11
30 static ImlibImagePixmap *pixmaps = NULL;
31 #endif
32 static int cache_size = 4096 * 1024;
33
34 __EXPORT__ DATA32 *
__imlib_AllocateData(ImlibImage * im)35 __imlib_AllocateData(ImlibImage * im)
36 {
37 int w = im->w;
38 int h = im->h;
39
40 if (w <= 0 || h <= 0)
41 return NULL;
42
43 if (im->data_memory_func)
44 im->data = im->data_memory_func(NULL, w * h * sizeof(DATA32));
45 else
46 im->data = malloc(w * h * sizeof(DATA32));
47
48 return im->data;
49 }
50
51 __EXPORT__ void
__imlib_FreeData(ImlibImage * im)52 __imlib_FreeData(ImlibImage * im)
53 {
54 if (im->data)
55 {
56 if (im->data_memory_func)
57 im->data_memory_func(im->data, im->w * im->h * sizeof(DATA32));
58 else
59 free(im->data);
60
61 im->data = NULL;
62 }
63 im->w = 0;
64 im->h = 0;
65 }
66
67 __EXPORT__ void
__imlib_ReplaceData(ImlibImage * im,unsigned int * new_data)68 __imlib_ReplaceData(ImlibImage * im, unsigned int *new_data)
69 {
70 if (im->data)
71 {
72 if (im->data_memory_func)
73 im->data_memory_func(im->data, im->w * im->h * sizeof(DATA32));
74 else
75 free(im->data);
76 }
77 im->data = new_data;
78 im->data_memory_func = NULL;
79 }
80
81 /* create an image data struct and fill it in */
82 static ImlibImage *
__imlib_ProduceImage(void)83 __imlib_ProduceImage(void)
84 {
85 ImlibImage *im;
86
87 im = calloc(1, sizeof(ImlibImage));
88 im->flags = F_FORMAT_IRRELEVANT | F_BORDER_IRRELEVANT | F_ALPHA_IRRELEVANT;
89
90 return im;
91 }
92
93 /* free an image struct */
94 static void
__imlib_ConsumeImage(ImlibImage * im)95 __imlib_ConsumeImage(ImlibImage * im)
96 {
97 #ifdef BUILD_X11
98 ImlibImagePixmap *ip;
99 #endif
100
101 __imlib_FreeAllTags(im);
102
103 if (im->real_file && im->real_file != im->file)
104 free(im->real_file);
105 if (im->file)
106 free(im->file);
107 if (im->key)
108 free(im->key);
109 if ((IMAGE_FREE_DATA(im)) && (im->data))
110 __imlib_FreeData(im);
111 if (im->format)
112 free(im->format);
113 free(im);
114 #ifdef BUILD_X11
115 ip = pixmaps;
116 while (ip)
117 {
118 if (ip->image == im)
119 {
120 ip->image = NULL;
121 ip->dirty = 1;
122 }
123 ip = ip->next;
124 }
125 #endif
126 }
127
128 static ImlibImage *
__imlib_FindCachedImage(const char * file)129 __imlib_FindCachedImage(const char *file)
130 {
131 ImlibImage *im, *previous_im;
132
133 im = images;
134 previous_im = NULL;
135 /* go through the images list */
136 while (im)
137 {
138 /* if the filenames match and it's valid */
139 if ((!strcmp(file, im->file)) && (IMAGE_IS_VALID(im)))
140 {
141 /* move the image to the head of the pixmap list */
142 if (previous_im)
143 {
144 previous_im->next = im->next;
145 im->next = images;
146 images = im;
147 }
148 /* return it */
149 return im;
150 }
151 previous_im = im;
152 im = im->next;
153 }
154 return NULL;
155 }
156
157 /* add an image to the cache of images (at the start) */
158 static void
__imlib_AddImageToCache(ImlibImage * im)159 __imlib_AddImageToCache(ImlibImage * im)
160 {
161 im->next = images;
162 images = im;
163 }
164
165 /* remove (unlink) an image from the cache of images */
166 static void
__imlib_RemoveImageFromCache(ImlibImage * im)167 __imlib_RemoveImageFromCache(ImlibImage * im)
168 {
169 ImlibImage *current_im, *previous_im;
170
171 current_im = images;
172 previous_im = NULL;
173 while (current_im)
174 {
175 if (im == current_im)
176 {
177 if (previous_im)
178 previous_im->next = im->next;
179 else
180 images = im->next;
181 return;
182 }
183 previous_im = current_im;
184 current_im = current_im->next;
185 }
186 }
187
188 /* work out how much we have floaitng aroudn in our speculative cache */
189 /* (images and pixmaps that have 0 reference counts) */
190 int
__imlib_CurrentCacheSize(void)191 __imlib_CurrentCacheSize(void)
192 {
193 ImlibImage *im;
194
195 #ifdef BUILD_X11
196 ImlibImagePixmap *ip;
197 #endif
198 int current_cache = 0;
199
200 /* go through the image cache */
201 im = images;
202 while (im)
203 {
204 /* mayaswell clean out stuff thats invalid that we dont need anymore */
205 if (im->references == 0)
206 {
207 if (!(IMAGE_IS_VALID(im)))
208 {
209 ImlibImage *tmp_im;
210
211 tmp_im = im;
212 im = im->next;
213 __imlib_RemoveImageFromCache(tmp_im);
214 __imlib_ConsumeImage(tmp_im);
215 continue;
216 }
217 /* it's valid but has 0 ref's - append to cache size count */
218 else
219 current_cache += im->w * im->h * sizeof(DATA32);
220 }
221 im = im->next;
222 }
223
224 #ifdef BUILD_X11
225 /* go through the pixmaps */
226 ip = pixmaps;
227 while (ip)
228 {
229 /* if the pixmap has 0 references */
230 if (ip->references == 0)
231 {
232 /* if the image is invalid */
233 if ((ip->dirty) || ((ip->image) && (!(IMAGE_IS_VALID(ip->image)))))
234 {
235 ImlibImagePixmap *tmp_ip;
236
237 tmp_ip = ip;
238 ip = ip->next;
239 __imlib_RemoveImagePixmapFromCache(tmp_ip);
240 __imlib_ConsumeImagePixmap(tmp_ip);
241 continue;
242 }
243 else
244 {
245 /* add the pixmap data size to the cache size */
246 if (ip->pixmap)
247 {
248 if (ip->depth < 8)
249 current_cache += ip->w * ip->h * (ip->depth / 8);
250 else if (ip->depth == 8)
251 current_cache += ip->w * ip->h;
252 else if (ip->depth <= 16)
253 current_cache += ip->w * ip->h * 2;
254 else if (ip->depth <= 32)
255 current_cache += ip->w * ip->h * 4;
256 }
257 /* if theres a mask add it too */
258 if (ip->mask)
259 current_cache += ip->w * ip->h / 8;
260 }
261 }
262 ip = ip->next;
263 }
264 #endif
265 return current_cache;
266 }
267
268 /* clean out images from the cache if the cache is overgrown */
269 static void
__imlib_CleanupImageCache(void)270 __imlib_CleanupImageCache(void)
271 {
272 ImlibImage *im, *im_last;
273 int current_cache;
274
275 current_cache = __imlib_CurrentCacheSize();
276 im_last = NULL;
277 im = images;
278 /* remove 0 ref count invalid (dirty) images */
279 while (im)
280 {
281 im_last = im;
282 im = im->next;
283 if ((im_last->references <= 0) && (!(IMAGE_IS_VALID(im_last))))
284 {
285 __imlib_RemoveImageFromCache(im_last);
286 __imlib_ConsumeImage(im_last);
287 }
288 }
289 /* while the cache size of 0 ref coutn data is bigger than the set value */
290 /* clean out the oldest members of the imaeg cache */
291 while (current_cache > cache_size)
292 {
293 im_last = NULL;
294 im = images;
295 while (im)
296 {
297 if (im->references <= 0)
298 im_last = im;
299 im = im->next;
300 }
301 if (!im_last)
302 break;
303
304 __imlib_RemoveImageFromCache(im_last);
305 __imlib_ConsumeImage(im_last);
306
307 current_cache = __imlib_CurrentCacheSize();
308 }
309 }
310
311 /* set the cache size */
312 void
__imlib_SetCacheSize(int size)313 __imlib_SetCacheSize(int size)
314 {
315 cache_size = size;
316 __imlib_CleanupImageCache();
317 #ifdef BUILD_X11
318 __imlib_CleanupImagePixmapCache();
319 #endif
320 }
321
322 /* return the cache size */
323 int
__imlib_GetCacheSize(void)324 __imlib_GetCacheSize(void)
325 {
326 return cache_size;
327 }
328
329 #ifdef BUILD_X11
330 /* create a pixmap cache data struct */
331 ImlibImagePixmap *
__imlib_ProduceImagePixmap(void)332 __imlib_ProduceImagePixmap(void)
333 {
334 ImlibImagePixmap *ip;
335
336 ip = calloc(1, sizeof(ImlibImagePixmap));
337
338 return ip;
339 }
340
341 /* free a pixmap cache data struct and the pixmaps in it */
342 void
__imlib_ConsumeImagePixmap(ImlibImagePixmap * ip)343 __imlib_ConsumeImagePixmap(ImlibImagePixmap * ip)
344 {
345 #ifdef DEBUG_CACHE
346 fprintf(stderr,
347 "[Imlib2] Deleting pixmap. Reference count is %d, pixmap 0x%08x, mask 0x%08x\n",
348 ip->references, ip->pixmap, ip->mask);
349 #endif
350 if (ip->pixmap)
351 XFreePixmap(ip->display, ip->pixmap);
352 if (ip->mask)
353 XFreePixmap(ip->display, ip->mask);
354 if (ip->file)
355 free(ip->file);
356 free(ip);
357 }
358
359 ImlibImagePixmap *
__imlib_FindCachedImagePixmap(ImlibImage * im,int w,int h,Display * d,Visual * v,int depth,int sx,int sy,int sw,int sh,Colormap cm,char aa,char hiq,char dmask,DATABIG modification_count)360 __imlib_FindCachedImagePixmap(ImlibImage * im, int w, int h, Display * d,
361 Visual * v, int depth, int sx, int sy, int sw,
362 int sh, Colormap cm, char aa, char hiq,
363 char dmask, DATABIG modification_count)
364 {
365 ImlibImagePixmap *ip, *previous_ip;
366
367 ip = pixmaps;
368 previous_ip = NULL;
369 /* go through the pixmap list */
370 while (ip)
371 {
372 /* if all the pixmap attributes match */
373 if ((ip->w == w) && (ip->h == h) && (ip->depth == depth) && (!ip->dirty)
374 && (ip->visual == v) && (ip->display == d)
375 && (ip->source_x == sx) && (ip->source_x == sy)
376 && (ip->source_w == sw) && (ip->source_h == sh)
377 && (ip->colormap == cm) && (ip->antialias == aa)
378 && (ip->modification_count == modification_count)
379 && (ip->dither_mask == dmask)
380 && (ip->border.left == im->border.left)
381 && (ip->border.right == im->border.right)
382 && (ip->border.top == im->border.top)
383 && (ip->border.bottom == im->border.bottom) &&
384 (((im->file) && (ip->file) && !strcmp(im->file, ip->file)) ||
385 ((!im->file) && (!ip->file) && (im == ip->image))))
386 {
387 /* move the pixmap to the head of the pixmap list */
388 if (previous_ip)
389 {
390 previous_ip->next = ip->next;
391 ip->next = pixmaps;
392 pixmaps = ip;
393 }
394 /* return it */
395 return ip;
396 }
397 previous_ip = ip;
398 ip = ip->next;
399 }
400 return NULL;
401 }
402
403 ImlibImagePixmap *
__imlib_FindCachedImagePixmapByID(Display * d,Pixmap p)404 __imlib_FindCachedImagePixmapByID(Display * d, Pixmap p)
405 {
406 ImlibImagePixmap *ip;
407
408 ip = pixmaps;
409 /* go through the pixmap list */
410 while (ip)
411 {
412 /* if all the pixmap attributes match */
413 if ((ip->pixmap == p) && (ip->display == d))
414 return ip;
415 ip = ip->next;
416 }
417 return NULL;
418 }
419
420 /* add a pixmap cahce struct to the pixmap cache (at the start of course */
421 void
__imlib_AddImagePixmapToCache(ImlibImagePixmap * ip)422 __imlib_AddImagePixmapToCache(ImlibImagePixmap * ip)
423 {
424 ip->next = pixmaps;
425 pixmaps = ip;
426 }
427
428 /* remove a pixmap cache struct from the pixmap cache */
429 void
__imlib_RemoveImagePixmapFromCache(ImlibImagePixmap * ip)430 __imlib_RemoveImagePixmapFromCache(ImlibImagePixmap * ip)
431 {
432 ImlibImagePixmap *current_ip, *previous_ip;
433
434 current_ip = pixmaps;
435 previous_ip = NULL;
436 while (current_ip)
437 {
438 if (ip == current_ip)
439 {
440 if (previous_ip)
441 previous_ip->next = ip->next;
442 else
443 pixmaps = ip->next;
444 return;
445 }
446 previous_ip = current_ip;
447 current_ip = current_ip->next;
448 }
449 }
450
451 /* clean out 0 reference count & dirty pixmaps from the cache */
452 void
__imlib_CleanupImagePixmapCache(void)453 __imlib_CleanupImagePixmapCache(void)
454 {
455 ImlibImagePixmap *ip, *ip_last;
456 int current_cache;
457
458 current_cache = __imlib_CurrentCacheSize();
459 ip_last = NULL;
460 ip = pixmaps;
461 while (ip)
462 {
463 ip_last = ip;
464 ip = ip->next;
465 if ((ip_last->references <= 0) && (ip_last->dirty))
466 {
467 __imlib_RemoveImagePixmapFromCache(ip_last);
468 __imlib_ConsumeImagePixmap(ip_last);
469 }
470 }
471 while (current_cache > cache_size)
472 {
473 ip_last = NULL;
474 ip = pixmaps;
475 while (ip)
476 {
477 if (ip->references <= 0)
478 ip_last = ip;
479 ip = ip->next;
480 }
481 if (!ip_last)
482 break;
483
484 __imlib_RemoveImagePixmapFromCache(ip_last);
485 __imlib_ConsumeImagePixmap(ip_last);
486
487 current_cache = __imlib_CurrentCacheSize();
488 }
489 }
490 #endif
491
492 static int
__imlib_ErrorFromErrno(int err,int save)493 __imlib_ErrorFromErrno(int err, int save)
494 {
495 switch (err)
496 {
497 default:
498 return IMLIB_LOAD_ERROR_UNKNOWN;
499 /* standrad fopen() type errors translated */
500 case 0:
501 return IMLIB_LOAD_ERROR_NONE;
502 case EEXIST:
503 return IMLIB_LOAD_ERROR_FILE_DOES_NOT_EXIST;
504 case EISDIR:
505 return IMLIB_LOAD_ERROR_FILE_IS_DIRECTORY;
506 case EACCES:
507 case EROFS:
508 return (save) ? IMLIB_LOAD_ERROR_PERMISSION_DENIED_TO_WRITE :
509 IMLIB_LOAD_ERROR_PERMISSION_DENIED_TO_READ;
510 case ENAMETOOLONG:
511 return IMLIB_LOAD_ERROR_PATH_TOO_LONG;
512 case ENOENT:
513 return IMLIB_LOAD_ERROR_PATH_COMPONENT_NON_EXISTANT;
514 case ENOTDIR:
515 return IMLIB_LOAD_ERROR_PATH_COMPONENT_NOT_DIRECTORY;
516 case EFAULT:
517 return IMLIB_LOAD_ERROR_PATH_POINTS_OUTSIDE_ADDRESS_SPACE;
518 case ELOOP:
519 return IMLIB_LOAD_ERROR_TOO_MANY_SYMBOLIC_LINKS;
520 case ENOMEM:
521 return IMLIB_LOAD_ERROR_OUT_OF_MEMORY;
522 case EMFILE:
523 return IMLIB_LOAD_ERROR_OUT_OF_FILE_DESCRIPTORS;
524 case ENOSPC:
525 return IMLIB_LOAD_ERROR_OUT_OF_DISK_SPACE;
526 }
527 }
528
529 static int
__imlib_FileCheck(const char * file,FILE * fp,struct stat * st,ImlibLoadError * er)530 __imlib_FileCheck(const char *file, FILE * fp, struct stat *st,
531 ImlibLoadError * er)
532 {
533 int err;
534
535 err = 0;
536
537 if (fp ? fstat(fileno(fp), st) : __imlib_FileStat(file, st))
538 err = IMLIB_LOAD_ERROR_FILE_DOES_NOT_EXIST;
539 else if (__imlib_StatIsDir(st))
540 err = IMLIB_LOAD_ERROR_FILE_IS_DIRECTORY;
541 else if (st->st_size == 0)
542 err = IMLIB_LOAD_ERROR_UNKNOWN;
543
544 if (er)
545 *er = err;
546
547 return err;
548 }
549
550 /* create a new image struct from data passed that is wize w x h then return */
551 /* a pointer to that image sturct */
552 ImlibImage *
__imlib_CreateImage(int w,int h,DATA32 * data)553 __imlib_CreateImage(int w, int h, DATA32 * data)
554 {
555 ImlibImage *im;
556
557 im = __imlib_ProduceImage();
558 im->w = w;
559 im->h = h;
560 im->data = data;
561 im->references = 1;
562 SET_FLAG(im->flags, F_UNCACHEABLE);
563 return im;
564 }
565
566 static int
__imlib_LoadImageWrapper(const ImlibLoader * l,ImlibImage * im,int load_data)567 __imlib_LoadImageWrapper(const ImlibLoader * l, ImlibImage * im, int load_data)
568 {
569 int rc;
570
571 if (l->load2)
572 {
573 FILE *fp = NULL;
574
575 if (!im->fp)
576 {
577 fp = im->fp = fopen(im->real_file, "rb");
578 if (!im->fp)
579 return 0;
580 }
581 rc = l->load2(im, load_data);
582
583 if (fp)
584 fclose(fp);
585 }
586 else if (l->load)
587 {
588 if (im->lc)
589 rc = l->load(im, im->lc->progress, im->lc->granularity, 1);
590 else
591 rc = l->load(im, NULL, 0, load_data);
592 }
593 else
594 {
595 return 0;
596 }
597
598 if (rc == 0)
599 {
600 /* Failed - clean up */
601 if (im->w != 0 || im->h != 0)
602 {
603 im->w = im->h = 0;
604 }
605 if (im->data)
606 {
607 __imlib_FreeData(im);
608 }
609 if (im->format)
610 {
611 free(im->format);
612 im->format = NULL;
613 }
614 }
615 else
616 {
617 if (!im->format && l->formats && l->formats[0])
618 im->format = strdup(l->formats[0]);
619 }
620
621 return rc;
622 }
623
624 static void
__imlib_LoadCtxInit(ImlibImage * im,ImlibLdCtx * lc,ImlibProgressFunction prog,int gran)625 __imlib_LoadCtxInit(ImlibImage * im, ImlibLdCtx * lc,
626 ImlibProgressFunction prog, int gran)
627 {
628 im->lc = lc;
629 lc->progress = prog;
630 lc->granularity = gran;
631 lc->pct = lc->row = 0;
632 lc->area = 0;
633 lc->pass = 0;
634 lc->n_pass = 1;
635 }
636
637 __EXPORT__ int
__imlib_LoadEmbedded(ImlibLoader * l,ImlibImage * im,const char * file,int load_data)638 __imlib_LoadEmbedded(ImlibLoader * l, ImlibImage * im, const char *file,
639 int load_data)
640 {
641 int rc;
642 char *file_save;
643 FILE *fp_save;
644
645 if (!l || !im)
646 return 0;
647
648 /* remember the original filename */
649 file_save = im->real_file;
650 im->real_file = strdup(file);
651 fp_save = im->fp;
652 im->fp = NULL;
653
654 rc = __imlib_LoadImageWrapper(l, im, load_data);
655
656 im->fp = fp_save;
657 free(im->real_file);
658 im->real_file = file_save;
659
660 return rc;
661 }
662
663 ImlibImage *
__imlib_LoadImage(const char * file,FILE * fp,ImlibProgressFunction progress,char progress_granularity,char immediate_load,char dont_cache,ImlibLoadError * er)664 __imlib_LoadImage(const char *file, FILE * fp, ImlibProgressFunction progress,
665 char progress_granularity, char immediate_load,
666 char dont_cache, ImlibLoadError * er)
667 {
668 ImlibImage *im;
669 ImlibLoader *best_loader;
670 int loader_ret;
671 ImlibLdCtx ilc;
672 struct stat st;
673
674 if (!file || file[0] == '\0')
675 return NULL;
676
677 /* see if we already have the image cached */
678 im = __imlib_FindCachedImage(file);
679
680 /* if we found a cached image and we should always check that it is */
681 /* accurate to the disk conents if they changed since we last loaded */
682 /* and that it is still a valid image */
683 if ((im) && (IMAGE_IS_VALID(im)))
684 {
685 if (IMAGE_ALWAYS_CHECK_DISK(im))
686 {
687 time_t current_modified_time;
688
689 current_modified_time = fp ?
690 __imlib_FileModDateFd(fileno(fp)) :
691 __imlib_FileModDate(im->real_file);
692 /* if the file on disk is newer than the cached one */
693 if (current_modified_time != im->moddate)
694 {
695 /* invalidate image */
696 SET_FLAG(im->flags, F_INVALID);
697 }
698 else
699 {
700 /* image is ok to re-use - program is just being stupid loading */
701 /* the same data twice */
702 im->references++;
703 return im;
704 }
705 }
706 else
707 {
708 im->references++;
709 return im;
710 }
711 }
712
713 if (__imlib_FileCheck(file, fp, &st, er))
714 return NULL;
715
716 /* either image in cache is invalid or we dont even have it in cache */
717 /* so produce a new one and load an image into that */
718 im = __imlib_ProduceImage();
719 im->file = strdup(file);
720
721 if (__imlib_StatIsFile(&st))
722 {
723 im->real_file = im->file;
724 im->key = NULL;
725 }
726 else
727 {
728 im->real_file = __imlib_FileRealFile(file);
729 im->key = __imlib_FileKey(file);
730 }
731
732 if (fp)
733 im->fp = fp;
734 else
735 im->fp = fopen(im->real_file, "rb");
736
737 if (!im->fp)
738 {
739 if (er)
740 *er = __imlib_ErrorFromErrno(errno, 0);
741 __imlib_ConsumeImage(im);
742 return NULL;
743 }
744
745 im->moddate = __imlib_StatModDate(&st);
746
747 im->data_memory_func = imlib_context_get_image_data_memory_function();
748
749 if (progress)
750 {
751 __imlib_LoadCtxInit(im, &ilc, progress, progress_granularity);
752 immediate_load = 1;
753 }
754
755 __imlib_LoadAllLoaders();
756
757 loader_ret = 0;
758
759 /* take a guess by extension on the best loader to use */
760 best_loader = __imlib_FindBestLoaderForFile(im->real_file, 0);
761 errno = 0;
762 if (best_loader)
763 loader_ret = __imlib_LoadImageWrapper(best_loader, im, immediate_load);
764
765 if (loader_ret > 0)
766 {
767 im->loader = best_loader;
768 }
769 else
770 {
771 ImlibLoader **loaders = __imlib_GetLoaderList();
772 ImlibLoader *l, *previous_l;
773
774 errno = 0;
775 /* run through all loaders and try load until one succeeds */
776 for (l = *loaders, previous_l = NULL; l; previous_l = l, l = l->next)
777 {
778 /* if its not the best loader that already failed - try load */
779 if (l == best_loader)
780 continue;
781 rewind(im->fp);
782 loader_ret = __imlib_LoadImageWrapper(l, im, immediate_load);
783 if (loader_ret > 0)
784 break;
785 }
786
787 /* if we have a loader then its the loader that succeeded */
788 /* move the successful loader to the head of the list */
789 /* as long as it's not already at the head of the list */
790 if (l)
791 {
792 im->loader = l;
793 if (previous_l)
794 {
795 previous_l->next = l->next;
796 l->next = *loaders;
797 *loaders = l;
798 }
799 }
800 }
801
802 im->lc = NULL;
803
804 if (!fp)
805 fclose(im->fp);
806 im->fp = NULL;
807
808 /* all loaders have been tried and they all failed. free the skeleton */
809 /* image struct we had and return NULL */
810 if (loader_ret <= 0)
811 {
812 /* if the caller wants an error return */
813 if (er)
814 *er = __imlib_ErrorFromErrno(errno, 0);
815 __imlib_ConsumeImage(im);
816 return NULL;
817 }
818
819 /* the load succeeded - make sure the image is referenced then add */
820 /* it to our cache if dont_cache isn't set */
821 im->references = 1;
822 if (loader_ret == 2)
823 dont_cache = 1;
824 if (!dont_cache)
825 __imlib_AddImageToCache(im);
826 else
827 SET_FLAG(im->flags, F_UNCACHEABLE);
828
829 return im;
830 }
831
832 int
__imlib_LoadImageData(ImlibImage * im)833 __imlib_LoadImageData(ImlibImage * im)
834 {
835 if (!im->data && im->loader)
836 if (__imlib_LoadImageWrapper(im->loader, im, 1) == 0)
837 return 1; /* Load failed */
838 return im->data == NULL;
839 }
840
841 __EXPORT__ void
__imlib_LoadProgressSetPass(ImlibImage * im,int pass,int n_pass)842 __imlib_LoadProgressSetPass(ImlibImage * im, int pass, int n_pass)
843 {
844 im->lc->pass = pass;
845 im->lc->n_pass = n_pass;
846
847 im->lc->row = 0;
848 }
849
850 __EXPORT__ int
__imlib_LoadProgress(ImlibImage * im,int x,int y,int w,int h)851 __imlib_LoadProgress(ImlibImage * im, int x, int y, int w, int h)
852 {
853 ImlibLdCtx *lc = im->lc;
854 int rc;
855
856 lc->area += w * h;
857 lc->pct = (100. * lc->area + .1) / (im->w * im->h);
858
859 rc = !lc->progress(im, lc->pct, x, y, w, h);
860
861 return rc;
862 }
863
864 __EXPORT__ int
__imlib_LoadProgressRows(ImlibImage * im,int row,int nrows)865 __imlib_LoadProgressRows(ImlibImage * im, int row, int nrows)
866 {
867 ImlibLdCtx *lc = im->lc;
868 int rc = 0;
869 int pct, nrtot;
870
871 if (nrows > 0)
872 {
873 /* Row index counting up */
874 nrtot = row + nrows;
875 row = lc->row;
876 nrows = nrtot - lc->row;
877 }
878 else
879 {
880 /* Row index counting down */
881 nrtot = im->h - row;
882 row = row;
883 nrows = nrtot - lc->row;
884 }
885
886 pct = (100 * nrtot * (lc->pass + 1)) / (im->h * lc->n_pass);
887 if (pct == 100 || pct >= lc->pct + lc->granularity)
888 {
889 rc = !lc->progress(im, pct, 0, row, im->w, nrows);
890 lc->row = nrtot;
891 lc->pct += lc->granularity;
892 }
893
894 return rc;
895 }
896
897 #ifdef BUILD_X11
898 /* find an imagepixmap cache entry by the display and pixmap id */
899 ImlibImagePixmap *
__imlib_FindImlibImagePixmapByID(Display * d,Pixmap p)900 __imlib_FindImlibImagePixmapByID(Display * d, Pixmap p)
901 {
902 ImlibImagePixmap *ip;
903
904 ip = pixmaps;
905 /* go through the pixmap list */
906 while (ip)
907 {
908 /* if all the pixmap ID & Display match */
909 if ((ip->pixmap == p) && (ip->display == d))
910 {
911 #ifdef DEBUG_CACHE
912 fprintf(stderr,
913 "[Imlib2] Match found. Reference count is %d, pixmap 0x%08x, mask 0x%08x\n",
914 ip->references, ip->pixmap, ip->mask);
915 #endif
916 return ip;
917 }
918 ip = ip->next;
919 }
920 return NULL;
921 }
922 #endif
923
924 /* free and image - if its uncachable and refcoutn is 0 - free it in reality */
925 void
__imlib_FreeImage(ImlibImage * im)926 __imlib_FreeImage(ImlibImage * im)
927 {
928 /* if the refcount is positive */
929 if (im->references >= 0)
930 {
931 /* reduce a reference from the count */
932 im->references--;
933 /* if its uncachchable ... */
934 if (IMAGE_IS_UNCACHEABLE(im))
935 {
936 /* and we're down to no references for the image then free it */
937 if (im->references == 0)
938 __imlib_ConsumeImage(im);
939 }
940 /* otherwise clean up our cache if the image becoem 0 ref count */
941 else if (im->references == 0)
942 __imlib_CleanupImageCache();
943 }
944 }
945
946 #ifdef BUILD_X11
947 /* free a cached pixmap */
948 void
__imlib_FreePixmap(Display * d,Pixmap p)949 __imlib_FreePixmap(Display * d, Pixmap p)
950 {
951 ImlibImagePixmap *ip;
952
953 /* find the pixmap in the cache by display and id */
954 ip = __imlib_FindImlibImagePixmapByID(d, p);
955 if (ip)
956 {
957 /* if tis positive reference count */
958 if (ip->references > 0)
959 {
960 /* dereference it by one */
961 ip->references--;
962 #ifdef DEBUG_CACHE
963 fprintf(stderr,
964 "[Imlib2] Reference count is now %d for pixmap 0x%08x\n",
965 ip->references, ip->pixmap);
966 #endif
967 /* if it becaume 0 reference count - clean the cache up */
968 if (ip->references == 0)
969 __imlib_CleanupImagePixmapCache();
970 }
971 }
972 else
973 {
974 #ifdef DEBUG_CACHE
975 fprintf(stderr, "[Imlib2] Pixmap 0x%08x not found. Freeing.\n", p);
976 #endif
977 XFreePixmap(d, p);
978 }
979 }
980
981 /* mark all pixmaps generated from this image as dirty so the cache code */
982 /* wont pick up on them again since they are now invalid since the original */
983 /* data they were generated from has changed */
984 void
__imlib_DirtyPixmapsForImage(ImlibImage * im)985 __imlib_DirtyPixmapsForImage(ImlibImage * im)
986 {
987 ImlibImagePixmap *ip;
988
989 ip = pixmaps;
990 /* go through the pixmap list */
991 while (ip)
992 {
993 /* if image matches */
994 if (ip->image == im)
995 ip->dirty = 1;
996 ip = ip->next;
997 }
998 __imlib_CleanupImagePixmapCache();
999 }
1000 #endif
1001
1002 /* dirty and image by settings its invalid flag */
1003 void
__imlib_DirtyImage(ImlibImage * im)1004 __imlib_DirtyImage(ImlibImage * im)
1005 {
1006 SET_FLAG(im->flags, F_INVALID);
1007 #ifdef BUILD_X11
1008 /* and dirty all pixmaps generated from it */
1009 __imlib_DirtyPixmapsForImage(im);
1010 #endif
1011 }
1012
1013 void
__imlib_SaveImage(ImlibImage * im,const char * file,ImlibProgressFunction progress,char progress_granularity,ImlibLoadError * er)1014 __imlib_SaveImage(ImlibImage * im, const char *file,
1015 ImlibProgressFunction progress, char progress_granularity,
1016 ImlibLoadError * er)
1017 {
1018 ImlibLoader *l;
1019 char e, *pfile;
1020 ImlibLdCtx ilc;
1021
1022 if (!file)
1023 {
1024 if (er)
1025 *er = IMLIB_LOAD_ERROR_FILE_DOES_NOT_EXIST;
1026 return;
1027 }
1028
1029 __imlib_LoadAllLoaders();
1030
1031 /* find the laoder for the format - if its null use the extension */
1032 l = __imlib_FindBestLoaderForFileFormat(file, im->format, 1);
1033 /* no loader - abort */
1034 if (!l)
1035 {
1036 if (er)
1037 *er = IMLIB_LOAD_ERROR_NO_LOADER_FOR_FILE_FORMAT;
1038 return;
1039 }
1040
1041 if (progress)
1042 __imlib_LoadCtxInit(im, &ilc, progress, progress_granularity);
1043
1044 /* set the filename to the user supplied one */
1045 pfile = im->real_file;
1046 im->real_file = strdup(file);
1047
1048 /* call the saver */
1049 e = l->save(im, progress, progress_granularity);
1050
1051 /* set the filename back to the laoder image filename */
1052 free(im->real_file);
1053 im->real_file = pfile;
1054
1055 im->lc = NULL;
1056
1057 if (er)
1058 *er = __imlib_ErrorFromErrno(e > 0 ? 0 : errno, 1);
1059 }
1060