1 /* -*- c-basic-offset:2; tab-width:2; indent-tabs-mode:nil -*- */
2 
3 #ifndef NO_IMAGE
4 
5 #include "../ui_imagelib.h"
6 
7 #include <stdio.h>  /* sprintf */
8 #include <unistd.h> /* write , STDIN_FILENO */
9 #if !defined(USE_WIN32API) && !defined(__ANDROID__)
10 #include <sys/wait.h> /* waitpid */
11 #endif
12 #ifdef DLOPEN_LIBM
13 #include <pobl/bl_dlfcn.h> /* dynamically loading pow */
14 #else
15 #include <math.h> /* pow */
16 #endif
17 #include <pobl/bl_debug.h>
18 #include <pobl/bl_mem.h>
19 #include <pobl/bl_path.h> /* BL_LIBEXECDIR */
20 
21 #include "ui_display.h" /* ui_cmap_get_closest_color */
22 
23 /* Trailing "/" is appended in value_table_refresh(). */
24 #ifndef LIBMDIR
25 #define LIBMDIR "/lib"
26 #endif
27 
28 #if 1
29 #define BUILTIN_SIXEL
30 #endif
31 
32 #ifdef USE_GRF
33 #define BPP_PSEUDO 2
34 #else
35 #define BPP_PSEUDO 1
36 #endif
37 
38 /* --- static functions --- */
39 
value_table_refresh(u_char * value_table,ui_picture_modifier_t * mod)40 static void value_table_refresh(u_char *value_table, /* 256 bytes */
41                                 ui_picture_modifier_t *mod) {
42   int i, tmp;
43   double real_gamma, real_brightness, real_contrast;
44   static double (*pow_func)(double, double);
45 
46   real_gamma = (double)(mod->gamma) / 100;
47   real_contrast = (double)(mod->contrast) / 100;
48   real_brightness = (double)(mod->brightness) / 100;
49 
50   if (!pow_func) {
51 #ifdef DLOPEN_LIBM
52     bl_dl_handle_t handle;
53 
54     if ((!(handle = bl_dl_open(LIBMDIR "/", "m")) && !(handle = bl_dl_open("", "m"))) ||
55         !(pow_func = bl_dl_func_symbol(handle, "pow"))) {
56 #ifdef DEBUG
57       bl_debug_printf(BL_DEBUG_TAG " Failed to load pow in libm.so\n");
58 #endif
59 
60       if (handle) {
61         bl_dl_close(handle);
62       }
63 
64       /*
65        * gamma, contrast and brightness options are ignored.
66        * (alpha option still survives.)
67        */
68       for (i = 0; i < 256; i++) {
69         value_table[i] = i;
70       }
71 
72       return;
73     }
74 
75     bl_dl_close_at_exit(handle);
76 #else  /* DLOPEN_LIBM */
77     pow_func = pow;
78 #endif /* DLOPEN_LIBM */
79   }
80 
81   for (i = 0; i < 256; i++) {
82     tmp = real_contrast * (255 * (*pow_func)(((double)i + 0.5) / 255, real_gamma) - 128) +
83           128 * real_brightness;
84     if (tmp >= 255) {
85       break;
86     } else if (tmp < 0) {
87       value_table[i] = 0;
88     } else {
89       value_table[i] = tmp;
90     }
91   }
92 
93   for (; i < 256; i++) {
94     value_table[i] = 255;
95   }
96 }
97 
modify_pixmap(Display * display,Pixmap pixmap,ui_picture_modifier_t * pic_mod,u_int depth)98 static void modify_pixmap(Display *display, Pixmap pixmap, ui_picture_modifier_t *pic_mod,
99                           u_int depth) {
100   u_char *value_table;
101   u_int32_t *src;
102   u_char *dst;
103   u_int num_pixels;
104   u_int count;
105   u_char r, g, b;
106   u_long pixel;
107 
108   if (!ui_picture_modifier_is_normal(pic_mod) && (value_table = alloca(256))) {
109     value_table_refresh(value_table, pic_mod);
110   } else if (display->bytes_per_pixel == 4 &&
111              /* RRGGBB */
112              display->rgbinfo.r_offset == 16 && display->rgbinfo.g_offset == 8 &&
113              display->rgbinfo.b_offset == 0) {
114     return;
115   } else {
116     value_table = NULL;
117   }
118 
119   src = dst = pixmap->image;
120   num_pixels = pixmap->width * pixmap->height;
121 
122   for (count = 0; count < num_pixels; count++) {
123     pixel = *(src++);
124 
125     r = (pixel >> 16) & 0xff;
126     g = (pixel >> 8) & 0xff;
127     b = pixel & 0xff;
128 
129     if (value_table) {
130       r = (value_table[r] * (255 - pic_mod->alpha) + pic_mod->blend_red * pic_mod->alpha) / 255;
131       g = (value_table[g] * (255 - pic_mod->alpha) + pic_mod->blend_green * pic_mod->alpha) / 255;
132       b = (value_table[b] * (255 - pic_mod->alpha) + pic_mod->blend_blue * pic_mod->alpha) / 255;
133     }
134 
135     if (ui_cmap_get_closest_color(&pixel, r, g, b)) {
136 #ifdef USE_GRF
137       *((u_int16_t *)dst) = pixel;
138       dst += 2;
139 #else
140       *(dst++) = pixel;
141 #endif
142     } else {
143       pixel = RGB_TO_PIXEL(r, g, b, display->rgbinfo) | (depth == 32 ? (pixel & 0xff000000) : 0);
144 
145       if (display->bytes_per_pixel == 2) {
146         *((u_int16_t *)dst) = pixel;
147         dst += 2;
148       } else /* if( display->bytes_per_pixel == 4) */
149       {
150         *((u_int32_t *)dst) = pixel;
151         dst += 4;
152       }
153     }
154   }
155 
156   if (display->bytes_per_pixel < 4) {
157     void *p;
158 
159     if ((p = realloc(pixmap->image, pixmap->width * pixmap->height * display->bytes_per_pixel))) {
160       pixmap->image = p;
161     }
162   }
163 }
164 
165 #ifdef BUILTIN_SIXEL
166 
167 #include <string.h>
168 #include <pobl/bl_util.h>
169 #include <pobl/bl_def.h> /* SSIZE_MAX */
170 
171 /*
172  * This function resizes the sixel image to the specified size and shrink
173  * pixmap->image.
174  * It frees pixmap->image in failure.
175  * Call resize_sixel() after load_sixel_from_file() because it returns at least
176  * 1024*1024 pixels memory even if the actual image size is less than 1024*1024.
177  */
resize_sixel(Pixmap pixmap,u_int width,u_int height,u_int bytes_per_pixel)178 static int resize_sixel(Pixmap pixmap, u_int width, u_int height, u_int bytes_per_pixel) {
179   void *p;
180   size_t line_len;
181   size_t old_line_len;
182   size_t image_len;
183   size_t old_image_len;
184   u_char *dst;
185   u_char *src;
186   int y;
187   u_int min_height;
188 
189   p = NULL;
190 
191   if ((width == 0 || width == pixmap->width) && (height == 0 || height == pixmap->height)) {
192     goto end;
193   }
194 
195   if (width > SSIZE_MAX / bytes_per_pixel / height) {
196     goto error;
197   }
198 
199   old_line_len = pixmap->width * bytes_per_pixel;
200   line_len = width * bytes_per_pixel;
201   image_len = line_len * height;
202   old_image_len = old_line_len * pixmap->height;
203 
204   if (image_len > old_image_len) {
205     if (!(p = realloc(pixmap->image, image_len))) {
206       goto error;
207     }
208 
209     pixmap->image = p;
210   }
211 
212   /* Tiling */
213 
214   min_height = BL_MIN(height, pixmap->height);
215 
216   if (width > pixmap->width) {
217     size_t surplus;
218     u_int num_copy;
219     u_int count;
220     u_char *dst_next;
221 
222     y = min_height - 1;
223     src = pixmap->image + old_line_len * y;
224     dst = pixmap->image + line_len * y;
225 
226     surplus = line_len % old_line_len;
227     num_copy = line_len / old_line_len - 1;
228 
229     for (; y >= 0; y--) {
230       dst_next = memmove(dst, src, old_line_len);
231 
232       for (count = num_copy; count > 0; count--) {
233         memcpy((dst_next += old_line_len), dst, old_line_len);
234       }
235       memcpy(dst_next + old_line_len, dst, surplus);
236 
237       dst -= line_len;
238       src -= old_line_len;
239     }
240   } else if (width < pixmap->width) {
241     src = pixmap->image + old_line_len;
242     dst = pixmap->image + line_len;
243 
244     for (y = 1; y < min_height; y++) {
245       memmove(dst, src, old_line_len);
246       dst += line_len;
247       src += old_line_len;
248     }
249   }
250 
251   if (height > pixmap->height) {
252     y = pixmap->height;
253     src = pixmap->image;
254     dst = src + line_len * y;
255 
256     for (; y < height; y++) {
257       memcpy(dst, src, line_len);
258       dst += line_len;
259       src += line_len;
260     }
261   }
262 
263   bl_msg_printf("Resize sixel from %dx%d to %dx%d\n", pixmap->width, pixmap->height, width, height);
264 
265   pixmap->width = width;
266   pixmap->height = height;
267 
268 end:
269   /* Always realloate pixmap->image according to its width, height and
270    * bytes_per_pixel. */
271   if (!p && (p = realloc(pixmap->image, pixmap->width * pixmap->height * bytes_per_pixel))) {
272     pixmap->image = p;
273   }
274 
275   return 1;
276 
277 error:
278   free(pixmap->image);
279 
280   return 0;
281 }
282 
283 #define CARD_HEAD_SIZE 0
284 #include "../../common/c_sixel.c"
285 
286 
287 /* For old machines (not to use mlimgloader) */
288 #if (defined(__NetBSD__) || defined(__OpenBSD__)) && !defined(USE_GRF)
289 
290 #define SIXEL_1BPP
291 #include "../../common/c_sixel.c"
292 #undef SIXEL_1BPP
293 
294 /* depth should be checked by the caller. */
load_sixel_with_mask_from_data_1bpp(char * file_data,u_int width,u_int height,Pixmap * pixmap,PixmapMask * mask)295 static int load_sixel_with_mask_from_data_1bpp(char *file_data, u_int width, u_int height,
296                                                Pixmap *pixmap, PixmapMask *mask) {
297   int x;
298   int y;
299   u_char *src;
300 #if 0
301   u_char *dst;
302 #endif
303 
304   if (!(*pixmap = calloc(1, sizeof(**pixmap)))) {
305     return 0;
306   }
307 
308   if (!((*pixmap)->image =
309             load_sixel_from_data_1bpp(file_data, &(*pixmap)->width, &(*pixmap)->height)) ||
310       /* resize_sixel() frees pixmap->image in failure. */
311       !resize_sixel(*pixmap, width, height, 1)) {
312     free(*pixmap);
313 
314     return 0;
315   }
316 
317   src = (*pixmap)->image;
318 
319 #if 0
320   if (mask && (dst = *mask = calloc(1, (*pixmap)->width * (*pixmap)->height))) {
321     int has_tp;
322 
323     has_tp = 0;
324 
325     for (y = 0; y < (*pixmap)->height; y++) {
326       for (x = 0; x < (*pixmap)->width; x++) {
327         if (*src >= 0x80) {
328           *dst = 1;
329           /* clear opaque mark */
330           *src &= 0x7f;
331         } else {
332           has_tp = 1;
333         }
334 
335         src++;
336         dst++;
337       }
338     }
339 
340     if (!has_tp) {
341       free(*mask);
342       *mask = None;
343     }
344   } else {
345     for (y = 0; y < (*pixmap)->height; y++) {
346       for (x = 0; x < (*pixmap)->width; x++) {
347         /* clear opaque mark */
348         *(src++) &= 0x7f;
349       }
350     }
351   }
352 #else
353   {
354     u_char bg_color;
355     u_char *p;
356 
357     if (mask) {
358       *mask = None;
359     }
360 
361     bg_color = 0;
362     p = src;
363 
364     /* Guess the current screen background color. */
365     for (y = 0; y < (*pixmap)->height; y++) {
366       for (x = 0; x < (*pixmap)->width; x++) {
367         if (*p >= 0x80) {
368           bg_color = (((*p) & 0x7f) == 1) ? 0 : 1;
369           break;
370         }
371 
372         p++;
373       }
374     }
375 
376     for (y = 0; y < (*pixmap)->height; y++) {
377       for (x = 0; x < (*pixmap)->width; x++) {
378         if (*src >= 0x80) {
379           /* clear opaque mark */
380           *(src++) &= 0x7f;
381         } else {
382           /* replace transparent pixel by the background color */
383           *(src++) = bg_color;
384         }
385       }
386     }
387   }
388 #endif
389 
390   return 1;
391 }
392 #endif
393 #endif /* BUILTIN_SIXEL */
394 
395 #define SIXEL_SHAREPALETTE
396 #include "../../common/c_sixel.c"
397 #undef SIXEL_SHAREPALETTE
398 
399 #if defined(USE_WIN32API)
400 #include <windows.h>
401 
exec_mlimgloader(char * path,u_int width,u_int height,int keep_aspect,Pixmap * pixmap)402 static int exec_mlimgloader(char *path, u_int width, u_int height, int keep_aspect,
403                             Pixmap *pixmap) {
404   HANDLE input_write;
405   HANDLE input_read_tmp;
406   HANDLE input_read;
407   SECURITY_ATTRIBUTES sa;
408   PROCESS_INFORMATION pi;
409   STARTUPINFO si;
410   char *cmd_line;
411   DWORD len;
412   ssize_t size;
413   u_int32_t tmp;
414 
415   sa.nLength = sizeof(SECURITY_ATTRIBUTES);
416   sa.lpSecurityDescriptor = NULL;
417   sa.bInheritHandle = TRUE;
418 
419   if (!CreatePipe(&input_read_tmp, &input_write, &sa, 0)) {
420 #ifdef DEBUG
421     bl_warn_printf(BL_DEBUG_TAG " CreatePipe() failed.\n");
422 #endif
423 
424     return 0;
425   }
426 
427   if (!DuplicateHandle(GetCurrentProcess(), input_read_tmp, GetCurrentProcess(),
428                        &input_read /* Address of new handle. */,
429                        0, FALSE /* Make it uninheritable. */,
430                        DUPLICATE_SAME_ACCESS)) {
431 #ifdef DEBUG
432     bl_warn_printf(BL_DEBUG_TAG " DuplicateHandle() failed.\n");
433 #endif
434 
435     CloseHandle(input_read_tmp);
436 
437     goto error1;
438   }
439 
440   CloseHandle(input_read_tmp);
441 
442   ZeroMemory(&si, sizeof(STARTUPINFO));
443   si.cb = sizeof(STARTUPINFO);
444   si.dwFlags = STARTF_USESTDHANDLES | STARTF_FORCEOFFFEEDBACK;
445   si.hStdOutput = input_write;
446   si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
447   si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
448   /*
449    * Use this if you want to hide the child:
450    *  si.wShowWindow = SW_HIDE;
451    * Note that dwFlags must include STARTF_USESHOWWINDOW if you want to
452    * use the wShowWindow flags.
453    */
454 
455   if ((cmd_line = alloca(23 + DIGIT_STR_LEN(u_int) * 2 + strlen(path) + 1)) == NULL) {
456 #ifdef DEBUG
457     bl_warn_printf(BL_DEBUG_TAG " alloca failed.\n");
458 #endif
459 
460     goto error1;
461   }
462 
463   sprintf(cmd_line, "%s 0 %d %d %s stdout%s", "mlimgloader.exe", width, height, path,
464           keep_aspect ? " -a" : "");
465 
466   if (!CreateProcess("mlimgloader.exe", cmd_line, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL,
467                      &si, &pi)) {
468 #ifdef DEBUG
469     bl_warn_printf(BL_DEBUG_TAG " CreateProcess() failed.\n");
470 #endif
471 
472     goto error1;
473   }
474 
475   CloseHandle(pi.hProcess);
476   CloseHandle(pi.hThread);
477 
478   CloseHandle(input_write);
479 
480   if (!(*pixmap = calloc(1, sizeof(**pixmap)))) {
481     goto error2;
482   }
483 
484   if (!ReadFile(input_read, &tmp, sizeof(u_int32_t), &len, NULL) || len != sizeof(u_int32_t)) {
485     goto error2;
486   }
487 
488   size = ((*pixmap)->width = tmp) * sizeof(u_int32_t);
489 
490   if (!ReadFile(input_read, &tmp, sizeof(u_int32_t), &len, NULL) || len != sizeof(u_int32_t)) {
491     goto error2;
492   }
493 
494   size *= ((*pixmap)->height = tmp);
495 
496   if (!((*pixmap)->image = malloc(size))) {
497     goto error2;
498   } else {
499     u_char *p;
500 
501     p = (*pixmap)->image;
502     do {
503       if (!ReadFile(input_read, p, size, &len, NULL)) {
504         free((*pixmap)->image);
505         goto error2;
506       }
507       p += len;
508     } while ((size -= len) > 0);
509   }
510 
511   CloseHandle(input_read);
512 
513   return 1;
514 
515 error1:
516   CloseHandle(input_write);
517   CloseHandle(input_read);
518 
519   return 0;
520 
521 error2:
522   free(*pixmap);
523   CloseHandle(input_read);
524 
525   return 0;
526 }
527 
528 #elif defined(__ANDROID__)
529 
exec_mlimgloader(char * path,u_int width,u_int height,int keep_aspect,Pixmap * pixmap)530 static int exec_mlimgloader(char *path, u_int width, u_int height, int keep_aspect,
531                             Pixmap *pixmap) {
532   if (!(*pixmap = calloc(1, sizeof(**pixmap)))) {
533     return 0;
534   }
535 
536   (*pixmap)->width = width;
537   (*pixmap)->height = height;
538 
539   if (!((*pixmap)->image = ui_display_get_bitmap(path, &(*pixmap)->width, &(*pixmap)->height))) {
540     free(*pixmap);
541 
542     return 0;
543   }
544 
545   return 1;
546 }
547 
548 #else
549 
exec_mlimgloader(char * path,u_int width,u_int height,int keep_aspect,Pixmap * pixmap)550 static int exec_mlimgloader(char *path, u_int width, u_int height, int keep_aspect,
551                             Pixmap *pixmap) {
552   pid_t pid;
553   int fds[2];
554   ssize_t size;
555   u_int32_t tmp;
556 
557   if (pipe(fds) == -1) {
558     return 0;
559   }
560 
561   pid = fork();
562   if (pid == -1) {
563     close(fds[0]);
564     close(fds[0]);
565 
566     return 0;
567   }
568 
569   if (pid == 0) {
570     /* child process */
571 
572     char *args[8];
573     char width_str[DIGIT_STR_LEN(u_int) + 1];
574     char height_str[DIGIT_STR_LEN(u_int) + 1];
575 
576     args[0] = BL_LIBEXECDIR("mlterm") "/mlimgloader";
577     args[1] = "0";
578     sprintf(width_str, "%u", width);
579     args[2] = width_str;
580     sprintf(height_str, "%u", height);
581     args[3] = height_str;
582     args[4] = path;
583     args[5] = "stdout";
584     if (keep_aspect) {
585       args[6] = "-a";
586       args[7] = NULL;
587     } else {
588       args[6] = NULL;
589     }
590 
591     close(fds[0]);
592     if (dup2(fds[1], STDOUT_FILENO) != -1) {
593       execv(args[0], args);
594     }
595 
596     bl_msg_printf("Failed to exec %s.\n", args[0]);
597 
598     exit(1);
599   }
600 
601   close(fds[1]);
602 
603   if (!(*pixmap = calloc(1, sizeof(**pixmap)))) {
604     goto error;
605   }
606 
607   if (read(fds[0], &tmp, sizeof(u_int32_t)) != sizeof(u_int32_t)) {
608     goto error;
609   }
610 
611   size = ((*pixmap)->width = tmp) * sizeof(u_int32_t);
612 
613   if (read(fds[0], &tmp, sizeof(u_int32_t)) != sizeof(u_int32_t)) {
614     goto error;
615   }
616 
617   size *= ((*pixmap)->height = tmp);
618 
619   if (!((*pixmap)->image = malloc(size))) {
620     goto error;
621   } else {
622     u_char *p;
623     ssize_t n_rd;
624 
625     p = (*pixmap)->image;
626     while ((n_rd = read(fds[0], p, size)) > 0) {
627       p += n_rd;
628       size -= n_rd;
629     }
630 
631     if (size > 0) {
632       goto error;
633     }
634   }
635 
636   close(fds[0]);
637 
638   /* bl_pty_fork() in vt_pty_unix_new() may block without this in startup. */
639 #if 1
640   waitpid(pid, NULL, 0);
641 #endif
642 
643   return 1;
644 
645 error:
646 #ifdef DEBUG
647   bl_debug_printf(BL_DEBUG_TAG " Failed to load %s\n", path);
648 #endif
649 
650   if (*pixmap) {
651     free((*pixmap)->image);
652     free(*pixmap);
653   }
654 
655   close(fds[0]);
656 
657   return 0;
658 }
659 
660 #endif
661 
load_file(Display * display,char * path,u_int width,u_int height,int keep_aspect,ui_picture_modifier_t * pic_mod,u_int depth,Pixmap * pixmap,PixmapMask * mask)662 static int load_file(Display *display, char *path, u_int width, u_int height, int keep_aspect,
663                      ui_picture_modifier_t *pic_mod, u_int depth, Pixmap *pixmap,
664                      PixmapMask *mask) {
665   if (!path || !*path) {
666     return 0;
667   }
668 
669 #ifdef BUILTIN_SIXEL
670   if (strcasecmp(path + strlen(path) - 4, ".six") == 0) {
671     char *file_data;
672 
673     if (!(file_data = read_sixel_file(path))) {
674       return 0;
675     }
676 
677     /* For old machines */
678 #if (defined(__NetBSD__) || defined(__OpenBSD__)) && !defined(USE_GRF)
679     if (depth == 1) {
680       /* pic_mod is ignored. */
681       if (load_sixel_with_mask_from_data_1bpp(file_data, width, height, pixmap, mask)) {
682         free(file_data);
683         return 1;
684       }
685     } else
686 #endif
687     if (
688 /* For old machines and Android (not to use mlimgloader) */
689 #if !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__ANDROID__) && \
690     (!defined(__FreeBSD__) || !defined(PC98))
691         width == 0 && height == 0 &&
692 #endif
693         (*pixmap = calloc(1, sizeof(**pixmap)))) {
694 #ifdef WALL_PICTURE_SIXEL_REPLACES_SYSTEM_PALETTE
695       u_int32_t *sixel_cmap;
696 
697       if (ui_display_is_changeable_cmap()) {
698         goto skip_sharepalette;
699       }
700 #endif
701 
702       if (depth <= 8) {
703         if (ui_picture_modifier_is_normal(pic_mod) /* see modify_pixmap() */) {
704           if (((*pixmap)->image = load_sixel_from_data_sharepalette(file_data, &(*pixmap)->width,
705                                                                     &(*pixmap)->height)) &&
706               resize_sixel(*pixmap, width, height, BPP_PSEUDO)) {
707             if (mask) {
708               *mask = NULL;
709             }
710             free(file_data);
711 
712             goto loaded_nomodify;
713           }
714         }
715 
716         bl_msg_printf("Use closest colors for %s.\n", path);
717       }
718 
719 #ifdef WALL_PICTURE_SIXEL_REPLACES_SYSTEM_PALETTE
720     skip_sharepalette:
721       if (!(sixel_cmap = custom_palette) &&
722           (sixel_cmap = alloca(sizeof(*sixel_cmap) * (SIXEL_PALETTE_SIZE + 1)))) {
723         sixel_cmap[SIXEL_PALETTE_SIZE] = 0; /* No active palette */
724         custom_palette = sixel_cmap;
725       }
726 #endif
727 
728       if (((*pixmap)->image = load_sixel_from_data(file_data, &(*pixmap)->width,
729                                                    &(*pixmap)->height)) &&
730           /* resize_sixel() frees pixmap->image in failure. */
731           resize_sixel(*pixmap, width, height, 4)) {
732 #ifdef WALL_PICTURE_SIXEL_REPLACES_SYSTEM_PALETTE
733         if (sixel_cmap) {
734           /* see set_wall_picture() in ui_screen.c */
735           ui_display_set_cmap(sixel_cmap, sixel_cmap[SIXEL_PALETTE_SIZE]);
736         }
737 #endif
738         free(file_data);
739 
740         goto loaded;
741       } else {
742         free(*pixmap);
743       }
744     }
745 
746     free(file_data);
747   }
748 #endif /* BUILTIN_SIXEL */
749 
750   if (!exec_mlimgloader(path, width, height, keep_aspect, pixmap)) {
751     return 0;
752   }
753 
754 loaded:
755   if (mask) {
756     u_char *dst;
757 
758     if ((dst = *mask = calloc(1, (*pixmap)->width * (*pixmap)->height))) {
759       int x;
760       int y;
761       int has_tp;
762       u_int32_t *src;
763 
764       has_tp = 0;
765       src = (u_int32_t *)(*pixmap)->image;
766 
767       for (y = 0; y < (*pixmap)->height; y++) {
768         for (x = 0; x < (*pixmap)->width; x++) {
769           if (*(src++) >= 0x80000000) {
770             *dst = 1;
771           } else {
772             has_tp = 1;
773           }
774 
775           dst++;
776         }
777       }
778 
779       if (!has_tp) {
780         free(*mask);
781         *mask = None;
782       }
783     }
784   }
785 
786   modify_pixmap(display, *pixmap, pic_mod, depth);
787 
788 loaded_nomodify:
789 #ifdef DEBUG
790   bl_debug_printf(BL_DEBUG_TAG " %s(w %d h %d) is loaded%s.\n", path, (*pixmap)->width,
791                   (*pixmap)->height, (mask && *mask) ? " (has mask)" : "");
792 #endif
793 
794   return 1;
795 }
796 
797 /* --- global functions --- */
798 
ui_imagelib_display_opened(Display * display)799 void ui_imagelib_display_opened(Display *display) {}
800 
ui_imagelib_display_closed(Display * display)801 void ui_imagelib_display_closed(Display *display) {}
802 
ui_imagelib_load_file_for_background(ui_window_t * win,char * path,ui_picture_modifier_t * pic_mod)803 Pixmap ui_imagelib_load_file_for_background(ui_window_t *win, char *path,
804                                             ui_picture_modifier_t *pic_mod) {
805   Pixmap pixmap;
806 
807 #ifdef WALL_PICTURE_SIXEL_REPLACES_SYSTEM_PALETTE
808   ui_display_enable_to_change_cmap(1);
809 #endif
810 
811   if (!load_file(win->disp->display, path, ACTUAL_WIDTH(win), ACTUAL_HEIGHT(win), 0, pic_mod,
812                  win->disp->depth, &pixmap, NULL)) {
813     pixmap = None;
814   }
815 
816 #ifdef WALL_PICTURE_SIXEL_REPLACES_SYSTEM_PALETTE
817   ui_display_enable_to_change_cmap(0);
818 #endif
819 
820   return pixmap;
821 }
822 
ui_imagelib_root_pixmap_available(Display * display)823 int ui_imagelib_root_pixmap_available(Display *display) { return 0; }
824 
ui_imagelib_get_transparent_background(ui_window_t * win,ui_picture_modifier_t * pic_mod)825 Pixmap ui_imagelib_get_transparent_background(ui_window_t *win, ui_picture_modifier_t *pic_mod) {
826   return None;
827 }
828 
ui_imagelib_load_file(ui_display_t * disp,char * path,u_int32_t ** cardinal,Pixmap * pixmap,PixmapMask * mask,u_int * width,u_int * height,int keep_aspect)829 int ui_imagelib_load_file(ui_display_t *disp, char *path, u_int32_t **cardinal, Pixmap *pixmap,
830                           PixmapMask *mask, u_int *width, u_int *height, int keep_aspect) {
831   if (cardinal) {
832     return 0;
833   }
834 
835   if (!load_file(disp->display, path, *width, *height, keep_aspect, NULL, disp->depth,
836                  pixmap, mask)) {
837     return 0;
838   }
839 
840   if (*width == 0 || *height == 0 || keep_aspect) {
841     *width = (*pixmap)->width;
842     *height = (*pixmap)->height;
843   }
844 
845   return 1;
846 }
847 
ui_destroy_image(Display * display,Pixmap pixmap)848 void ui_destroy_image(Display *display, Pixmap pixmap) {
849   free(pixmap->image);
850   free(pixmap);
851 }
852 
ui_destroy_mask(Display * display,PixmapMask mask)853 void ui_destroy_mask(Display *display, PixmapMask mask /* can be NULL */) {
854   if (mask) {
855     free(mask);
856   }
857 }
858 
859 #endif /* NO_IMAGE */
860