This source file includes following definitions.
- image_create_pix_container
- image_pix_container_put_pixel
- image_pix_context_get_pixel
- image_pix_container_create_from_bitmap_data
- cr_create_surface_from_pix_containers
- cr_put_image_to_cr_data
- XGetPixel
- XPutPixel
- x_bitmap_height
- x_bitmap_width
- x_bitmap_stipple
- image_bitmap_pixmap
- x_bitmap_mask
- image_allocate_bitmap_record
- image_reference_bitmap
- image_create_pattern_from_pixbuf
- image_create_bitmap_from_data
- image_create_bitmap_from_file
- free_bitmap_record
- image_destroy_bitmap
- image_destroy_all_bitmaps
- x_create_bitmap_mask
- add_image_type
- valid_image_p
- image_error
- image_size_error
- parse_image_spec
- image_spec_value
- make_image
- free_image
- check_image_size
- prepare_image_for_display
- image_ascent
- four_corners_best
- image_background
- image_background_transparent
- image_clear_image_1
- image_clear_image
- image_alloc_image_color
- make_image_cache
- search_image_cache
- filter_image_spec
- uncache_image
- free_image_cache
- clear_image_cache
- clear_image_caches
- image_size_in_bytes
- image_frame_cache_size
- postprocess_image
- scale_image_size
- image_get_dimension
- compute_image_size
- matrix3x3_mult
- compute_image_rotation
- image_set_transform
- lookup_image
- cache_image
- anim_create_cache
- anim_prune_animation_cache
- anim_get_animation_cache
- mark_image
- mark_image_cache
- x_check_image_size
- x_create_x_image_and_pixmap
- x_destroy_x_image
- x_create_xrender_picture
- image_check_image_size
- image_create_x_image_and_pixmap_1
- image_destroy_x_image
- gui_put_x_image
- image_create_x_image_and_pixmap
- image_put_x_image
- image_sync_to_pixmaps
- image_get_x_image_or_dc
- image_unget_x_image_or_dc
- image_get_x_image
- image_unget_x_image
- image_find_image_fd
- image_find_image_file
- slurp_file
- xbm_image_p
- xbm_scan
- w32_create_pixmap_from_bitmap_data
- convert_mono_to_color_image
- Create_Pixmap_From_Bitmap_Data
- xbm_read_bitmap_data
- xbm_load_image
- xbm_file_p
- xbm_load
- xpm_init_color_cache
- xpm_free_color_cache
- xpm_color_bucket
- xpm_cache_color
- xpm_lookup_color
- xpm_alloc_color
- xpm_free_colors
- init_xpm_functions
- xpm_valid_color_symbols_p
- xpm_image_p
- x_create_bitmap_from_xpm_data
- xpm_load
- xpm_scan
- xpm_make_color_table_v
- xpm_put_color_table_v
- xpm_get_color_table_v
- xpm_make_color_table_h
- xpm_put_color_table_h
- xpm_get_color_table_h
- xpm_str_to_color_key
- xpm_load_image
- xpm_load
- ct_hash_rgb
- init_color_table
- free_color_table
- lookup_rgb_color
- lookup_pixel_color
- colors_in_color_table
- lookup_rgb_color
- init_color_table
- image_to_emacs_colors
- XPutPixel
- image_from_emacs_colors
- image_detect_edges
- image_emboss
- image_laplace
- image_edge_detection
- image_pixmap_draw_cross
- image_disable_image
- image_build_heuristic_mask
- pbm_image_p
- pbm_next_char
- pbm_scan_number
- pbm_scan_index
- pbm_load
- image_can_use_native_api
- native_image_p
- native_image_load
- png_image_p
- init_png_functions
- my_png_error
- my_png_warning
- png_read_from_memory
- png_read_from_file
- png_load_body
- png_load
- jpeg_image_p
- init_jpeg_functions
- jpeg_resync_to_restart_wrapper
- my_error_exit
- our_common_init_source
- our_common_term_source
- our_memory_fill_input_buffer
- our_memory_skip_input_data
- jpeg_memory_src
- our_stdio_fill_input_buffer
- our_stdio_skip_input_data
- jpeg_file_src
- jpeg_load_body
- jpeg_load
- tiff_image_p
- init_tiff_functions
- tiff_read_from_memory
- tiff_write_from_memory
- tiff_seek_in_memory
- tiff_close_memory
- tiff_mmap_memory
- tiff_unmap_memory
- tiff_size_of_memory
- tiff_handler
- tiff_error_handler
- tiff_warning_handler
- tiff_load
- gif_clear_image
- gif_image_p
- init_gif_functions
- gif_read_from_memory
- gif_close
- gif_destroy
- gif_load
- webp_image_p
- init_webp_functions
- webp_destroy
- webp_load
- imagemagick_clear_image
- imagemagick_image_p
- imagemagick_initialize
- imagemagick_error
- imagemagick_filename_hint
- imagemagick_create_cache
- imagemagick_prune_animation_cache
- imagemagick_get_animation_cache
- imagemagick_compute_animated_image
- imagemagick_load_image
- imagemagick_load
- DEFUN
- svg_image_p
- init_svg_functions
- svg_load
- svg_css_length_to_pixels
- svg_load_image
- gs_image_p
- gs_load
- x_kill_gs_process
- DEFUN
- DEFUN
- DEFUN
- DEFUN
- DEFUN
- initialize_image_type
- lookup_image_type
- image_prune_animation_caches
- syms_of_image
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 #include <config.h>
21
22 #include <fcntl.h>
23 #include <math.h>
24 #include <unistd.h>
25
26
27
28 #if defined HAVE_PNG
29 # include <png.h>
30 #endif
31
32 #include <setjmp.h>
33
34 #include <math.h>
35 #include <stdint.h>
36 #include <c-ctype.h>
37 #include <flexmember.h>
38
39 #include "lisp.h"
40 #include "frame.h"
41 #include "process.h"
42 #include "window.h"
43 #include "buffer.h"
44 #include "dispextern.h"
45 #include "blockinput.h"
46 #include "sysstdio.h"
47 #include "systime.h"
48 #include <epaths.h>
49 #include "coding.h"
50 #include "termhooks.h"
51 #include "font.h"
52 #include "pdumper.h"
53
54 #ifdef HAVE_SYS_STAT_H
55 #include <sys/stat.h>
56 #endif
57
58 #ifdef HAVE_SYS_TYPES_H
59 #include <sys/types.h>
60 #endif
61
62 #ifdef HAVE_WINDOW_SYSTEM
63 #include TERM_HEADER
64 #endif
65
66
67 #if GNUC_PREREQ (4, 3, 0)
68 # pragma GCC diagnostic ignored "-Wclobbered"
69 #endif
70
71 #ifdef HAVE_X_WINDOWS
72 typedef struct x_bitmap_record Bitmap_Record;
73 #ifndef USE_CAIRO
74 #define GET_PIXEL(ximg, x, y) XGetPixel (ximg, x, y)
75 #define PUT_PIXEL XPutPixel
76 #define NO_PIXMAP None
77
78 #define PIX_MASK_RETAIN 0
79 #define PIX_MASK_DRAW 1
80 #endif
81 #endif
82
83 #if defined(USE_CAIRO) || defined(HAVE_NS)
84 #define RGB_TO_ULONG(r, g, b) (((r) << 16) | ((g) << 8) | (b))
85 #ifndef HAVE_NS
86 #define ARGB_TO_ULONG(a, r, g, b) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
87 #endif
88 #define RED_FROM_ULONG(color) (((color) >> 16) & 0xff)
89 #define GREEN_FROM_ULONG(color) (((color) >> 8) & 0xff)
90 #define BLUE_FROM_ULONG(color) ((color) & 0xff)
91 #define RED16_FROM_ULONG(color) (RED_FROM_ULONG (color) * 0x101)
92 #define GREEN16_FROM_ULONG(color) (GREEN_FROM_ULONG (color) * 0x101)
93 #define BLUE16_FROM_ULONG(color) (BLUE_FROM_ULONG (color) * 0x101)
94 #endif
95
96 #ifdef USE_CAIRO
97 #define GET_PIXEL image_pix_context_get_pixel
98 #define PUT_PIXEL image_pix_container_put_pixel
99 #define NO_PIXMAP 0
100
101 #define PIX_MASK_RETAIN 0
102 #define PIX_MASK_DRAW 255
103
104 static unsigned long image_alloc_image_color (struct frame *, struct image *,
105 Lisp_Object, unsigned long);
106 #endif
107
108 #if defined HAVE_PGTK && defined HAVE_IMAGEMAGICK
109
110
111
112
113
114 # define DONT_CREATE_TRANSFORMED_IMAGEMAGICK_IMAGE
115 #endif
116
117 #ifdef HAVE_NTGUI
118
119
120 #ifdef WINDOWSNT
121 # include "w32common.h"
122 # include "w32.h"
123 #endif
124
125 typedef struct w32_bitmap_record Bitmap_Record;
126 #define GET_PIXEL(ximg, x, y) GetPixel (ximg, x, y)
127 #define PUT_PIXEL XPutPixel
128 #define NO_PIXMAP 0
129
130 #define PIX_MASK_RETAIN 0
131 #define PIX_MASK_DRAW 1
132
133 #endif
134
135 #ifdef HAVE_NS
136 typedef struct ns_bitmap_record Bitmap_Record;
137
138 #define GET_PIXEL(ximg, x, y) XGetPixel (ximg, x, y)
139 #define PUT_PIXEL XPutPixel
140 #define NO_PIXMAP 0
141
142 #define PIX_MASK_RETAIN 0
143 #define PIX_MASK_DRAW 1
144
145 #endif
146
147 #ifdef HAVE_PGTK
148 typedef struct pgtk_bitmap_record Bitmap_Record;
149 #endif
150
151 #if (defined HAVE_X_WINDOWS \
152 && ! (defined HAVE_NTGUI || defined USE_CAIRO || defined HAVE_NS))
153
154 # define COLOR_TABLE_SUPPORT 1
155 #endif
156
157 #ifdef HAVE_HAIKU
158 #include "haiku_support.h"
159 typedef struct haiku_bitmap_record Bitmap_Record;
160
161 #define GET_PIXEL(ximg, x, y) haiku_get_pixel (ximg, x, y)
162 #define PUT_PIXEL haiku_put_pixel
163 #define NO_PIXMAP 0
164
165 #define PIX_MASK_RETAIN 0
166 #define PIX_MASK_DRAW 1
167
168 #define RGB_TO_ULONG(r, g, b) (((r) << 16) | ((g) << 8) | (b))
169 #define RED_FROM_ULONG(color) (((color) >> 16) & 0xff)
170 #define GREEN_FROM_ULONG(color) (((color) >> 8) & 0xff)
171 #define BLUE_FROM_ULONG(color) ((color) & 0xff)
172 #define RED16_FROM_ULONG(color) (RED_FROM_ULONG (color) * 0x101)
173 #define GREEN16_FROM_ULONG(color) (GREEN_FROM_ULONG (color) * 0x101)
174 #define BLUE16_FROM_ULONG(color) (BLUE_FROM_ULONG (color) * 0x101)
175
176 #endif
177
178 static void image_disable_image (struct frame *, struct image *);
179 static void image_edge_detection (struct frame *, struct image *, Lisp_Object,
180 Lisp_Object);
181
182 static void init_color_table (void);
183 static unsigned long lookup_rgb_color (struct frame *f, int r, int g, int b);
184 #ifdef COLOR_TABLE_SUPPORT
185 static void free_color_table (void);
186 static unsigned long *colors_in_color_table (int *n);
187 #endif
188
189 #if defined (HAVE_WEBP) || defined (HAVE_GIF)
190 static void anim_prune_animation_cache (Lisp_Object);
191 #endif
192
193 #ifdef USE_CAIRO
194
195 static Emacs_Pix_Container
196 image_create_pix_container (unsigned int width, unsigned int height,
197 unsigned int depth)
198 {
199 Emacs_Pix_Container pimg;
200
201 pimg = xmalloc (sizeof (*pimg));
202 pimg->width = width;
203 pimg->height = height;
204 pimg->bits_per_pixel = depth == 1 ? 8 : 32;
205 pimg->bytes_per_line = cairo_format_stride_for_width ((depth == 1
206 ? CAIRO_FORMAT_A8
207 : CAIRO_FORMAT_RGB24),
208 width);
209 pimg->data = xmalloc (pimg->bytes_per_line * height);
210
211 return pimg;
212 }
213
214 static void
215 image_pix_container_put_pixel (Emacs_Pix_Container image,
216 int x, int y, unsigned long pixel)
217 {
218 if (image->bits_per_pixel == 32)
219 ((uint32_t *)(image->data + y * image->bytes_per_line))[x] = pixel;
220 else
221 ((uint8_t *)(image->data + y * image->bytes_per_line))[x] = pixel;
222 }
223
224 static unsigned long
225 image_pix_context_get_pixel (Emacs_Pix_Context image, int x, int y)
226 {
227 if (image->bits_per_pixel == 32)
228 return ((uint32_t *)(image->data + y * image->bytes_per_line))[x];
229 else
230 return ((uint8_t *)(image->data + y * image->bytes_per_line))[x];
231 }
232
233 static Emacs_Pix_Container
234 image_pix_container_create_from_bitmap_data (struct frame *f,
235 char *data, unsigned int width,
236 unsigned int height,
237 unsigned long fg,
238 unsigned long bg)
239 {
240 Emacs_Pix_Container pimg = image_create_pix_container (width, height, 0);
241 int bytes_per_line = (width + (CHAR_BIT - 1)) / CHAR_BIT;
242
243 for (int y = 0; y < height; y++)
244 {
245 for (int x = 0; x < width; x++)
246 PUT_PIXEL (pimg, x, y,
247 (data[x / CHAR_BIT] >> (x % CHAR_BIT)) & 1 ? fg : bg);
248 data += bytes_per_line;
249 }
250
251 return pimg;
252 }
253
254 static cairo_surface_t *
255 cr_create_surface_from_pix_containers (Emacs_Pix_Container pimg,
256 Emacs_Pix_Container mask)
257 {
258 cairo_surface_t *surface;
259
260 if (mask)
261 {
262 int x, y;
263
264 for (y = 0; y < pimg->height; y++)
265 for (x = 0; x < pimg->width; x++)
266 {
267 unsigned long color, alpha;
268 int r, g, b;
269
270 color = GET_PIXEL (pimg, x, y);
271 alpha = GET_PIXEL (mask, x, y);
272 r = (RED_FROM_ULONG (color) * alpha + 0x7f) / 0xff;
273 g = (GREEN_FROM_ULONG (color) * alpha + 0x7f) / 0xff;
274 b = (BLUE_FROM_ULONG (color) * alpha + 0x7f) / 0xff;
275 PUT_PIXEL (pimg, x, y, ARGB_TO_ULONG (alpha, r, g, b));
276 }
277 xfree (mask->data);
278 mask->data = NULL;
279 }
280 surface = cairo_image_surface_create_for_data ((unsigned char *) pimg->data,
281 (mask ? CAIRO_FORMAT_ARGB32
282 : CAIRO_FORMAT_RGB24),
283 pimg->width, pimg->height,
284 pimg->bytes_per_line);
285 static const cairo_user_data_key_t key;
286 cairo_surface_set_user_data (surface, &key, pimg->data, xfree);
287 pimg->data = NULL;
288
289 return surface;
290 }
291
292 static void
293 cr_put_image_to_cr_data (struct image *img)
294 {
295 cairo_pattern_t *pattern = NULL;
296 cairo_surface_t *surface = cr_create_surface_from_pix_containers (img->pixmap,
297 img->mask);
298 if (surface)
299 {
300 pattern = cairo_pattern_create_for_surface (surface);
301 if (img->cr_data)
302 {
303 cairo_matrix_t matrix;
304 cairo_pattern_get_matrix (img->cr_data, &matrix);
305 cairo_pattern_set_matrix (pattern, &matrix);
306 cairo_pattern_set_filter
307 (pattern, cairo_pattern_get_filter (img->cr_data));
308 cairo_pattern_destroy (img->cr_data);
309 }
310 cairo_surface_destroy (surface);
311 }
312
313 img->cr_data = pattern;
314 }
315
316 #endif
317
318 #ifdef HAVE_NS
319
320 static unsigned long
321 XGetPixel (Emacs_Pix_Container image, int x, int y)
322 {
323 return ns_get_pixel (image, x, y);
324 }
325
326
327
328 static void
329 XPutPixel (Emacs_Pix_Container image, int x, int y, unsigned long pixel)
330 {
331 ns_put_pixel (image, x, y, pixel);
332 }
333 #endif
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348 #ifdef HAVE_X_WINDOWS
349 static int
350 x_bitmap_height (struct frame *f, ptrdiff_t id)
351 {
352 return FRAME_DISPLAY_INFO (f)->bitmaps[id - 1].height;
353 }
354
355 static int
356 x_bitmap_width (struct frame *f, ptrdiff_t id)
357 {
358 return FRAME_DISPLAY_INFO (f)->bitmaps[id - 1].width;
359 }
360
361 #ifdef USE_CAIRO
362 cairo_pattern_t *
363 x_bitmap_stipple (struct frame *f, Pixmap pixmap)
364 {
365 Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
366
367 for (ptrdiff_t i = 0; i < dpyinfo->bitmaps_last; i++)
368 {
369 struct x_bitmap_record *bm = dpyinfo->bitmaps + i;
370
371 if (bm->refcount && bm->pixmap == pixmap && bm->depth == 1)
372 {
373 if (bm->stipple == NULL)
374 {
375 cairo_surface_t *surface
376 = cairo_xlib_surface_create_for_bitmap (FRAME_X_DISPLAY (f),
377 pixmap,
378 FRAME_X_SCREEN (f),
379 bm->width, bm->height);
380 cairo_pattern_t *pattern
381 = cairo_pattern_create_for_surface (surface);
382 cairo_surface_destroy (surface);
383 cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
384 bm->stipple = pattern;
385 }
386
387 return bm->stipple;
388 }
389 }
390
391 return NULL;
392 }
393
394 #endif
395 #endif
396
397 #if defined (HAVE_X_WINDOWS) || defined (HAVE_NTGUI)
398 ptrdiff_t
399 image_bitmap_pixmap (struct frame *f, ptrdiff_t id)
400 {
401
402 return (ptrdiff_t) FRAME_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
403 }
404 #endif
405
406 #ifdef HAVE_X_WINDOWS
407 int
408 x_bitmap_mask (struct frame *f, ptrdiff_t id)
409 {
410 return FRAME_DISPLAY_INFO (f)->bitmaps[id - 1].mask;
411 }
412 #endif
413
414
415
416 static ptrdiff_t
417 image_allocate_bitmap_record (struct frame *f)
418 {
419 Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
420 ptrdiff_t i;
421
422 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
423 return ++dpyinfo->bitmaps_last;
424
425 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
426 if (dpyinfo->bitmaps[i].refcount == 0)
427 return i + 1;
428
429 dpyinfo->bitmaps =
430 xpalloc (dpyinfo->bitmaps, &dpyinfo->bitmaps_size,
431 10, -1, sizeof *dpyinfo->bitmaps);
432 return ++dpyinfo->bitmaps_last;
433 }
434
435
436
437 void
438 image_reference_bitmap (struct frame *f, ptrdiff_t id)
439 {
440 ++FRAME_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
441 }
442
443 #ifdef HAVE_PGTK
444 static cairo_pattern_t *
445 image_create_pattern_from_pixbuf (struct frame *f, GdkPixbuf * pixbuf)
446 {
447 GdkPixbuf *pb = gdk_pixbuf_add_alpha (pixbuf, TRUE, 255, 255, 255);
448 cairo_surface_t *surface =
449 cairo_surface_create_similar_image (cairo_get_target
450 (f->output_data.pgtk->cr_context),
451 CAIRO_FORMAT_A1,
452 gdk_pixbuf_get_width (pb),
453 gdk_pixbuf_get_height (pb));
454
455 cairo_t *cr = cairo_create (surface);
456 gdk_cairo_set_source_pixbuf (cr, pb, 0, 0);
457 cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
458 cairo_paint (cr);
459 cairo_destroy (cr);
460
461 cairo_pattern_t *pat = cairo_pattern_create_for_surface (surface);
462 cairo_pattern_set_extend (pat, CAIRO_EXTEND_REPEAT);
463
464 cairo_surface_destroy (surface);
465 g_object_unref (pb);
466
467 return pat;
468 }
469 #endif
470
471
472
473 ptrdiff_t
474 image_create_bitmap_from_data (struct frame *f, char *bits,
475 unsigned int width, unsigned int height)
476 {
477 Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
478 ptrdiff_t id;
479
480 #ifdef HAVE_X_WINDOWS
481 Pixmap bitmap;
482 bitmap = XCreateBitmapFromData (FRAME_X_DISPLAY (f),
483 dpyinfo->root_window,
484 bits, width, height);
485 if (! bitmap)
486 return -1;
487 #endif
488
489 #ifdef HAVE_NTGUI
490 Lisp_Object frame UNINIT;
491 Emacs_Pixmap bitmap;
492 bitmap = CreateBitmap (width, height,
493 FRAME_DISPLAY_INFO (XFRAME (frame))->n_planes,
494 FRAME_DISPLAY_INFO (XFRAME (frame))->n_cbits,
495 bits);
496 if (! bitmap)
497 return -1;
498 #endif
499
500 #ifdef HAVE_NS
501 void *bitmap = ns_image_from_XBM (bits, width, height, 0, 0);
502 if (!bitmap)
503 return -1;
504 #endif
505
506 #ifdef HAVE_PGTK
507 GdkPixbuf *pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
508 FALSE,
509 8,
510 width,
511 height);
512 {
513 char *sp = bits;
514 int mask = 0x01;
515 unsigned char *buf = gdk_pixbuf_get_pixels (pixbuf);
516 int rowstride = gdk_pixbuf_get_rowstride (pixbuf);
517 for (int y = 0; y < height; y++)
518 {
519 unsigned char *dp = buf + rowstride * y;
520 for (int x = 0; x < width; x++)
521 {
522 if (*sp & mask)
523 {
524 *dp++ = 0xff;
525 *dp++ = 0xff;
526 *dp++ = 0xff;
527 }
528 else
529 {
530 *dp++ = 0x00;
531 *dp++ = 0x00;
532 *dp++ = 0x00;
533 }
534 if ((mask <<= 1) >= 0x100)
535 {
536 mask = 0x01;
537 sp++;
538 }
539 }
540 if (mask != 0x01)
541 {
542 mask = 0x01;
543 sp++;
544 }
545 }
546 }
547 #endif
548
549 #ifdef HAVE_HAIKU
550 void *bitmap, *stipple;
551 int bytes_per_line, x, y;
552
553 bitmap = BBitmap_new (width, height, false);
554
555 if (!bitmap)
556 return -1;
557
558 bytes_per_line = (width + 7) / 8;
559 stipple = xmalloc (height * bytes_per_line);
560 memcpy (stipple, bits, height * bytes_per_line);
561
562 for (y = 0; y < height; y++)
563 {
564 for (x = 0; x < width; x++)
565 PUT_PIXEL (bitmap, x, y, ((bits[8] >> (x % 8)) & 1
566 ? f->foreground_pixel
567 : f->background_pixel));
568 bits += bytes_per_line;
569 }
570 #endif
571
572 id = image_allocate_bitmap_record (f);
573
574 #ifdef HAVE_NS
575 dpyinfo->bitmaps[id - 1].img = bitmap;
576 dpyinfo->bitmaps[id - 1].depth = 1;
577 #endif
578
579 #ifdef HAVE_PGTK
580 dpyinfo->bitmaps[id - 1].img = pixbuf;
581 dpyinfo->bitmaps[id - 1].depth = 1;
582 dpyinfo->bitmaps[id - 1].pattern =
583 image_create_pattern_from_pixbuf (f, pixbuf);
584 #endif
585
586 #ifdef HAVE_HAIKU
587 dpyinfo->bitmaps[id - 1].img = bitmap;
588 dpyinfo->bitmaps[id - 1].depth = 1;
589 dpyinfo->bitmaps[id - 1].stipple_bits = stipple;
590 dpyinfo->bitmaps[id - 1].stipple_foreground
591 = f->foreground_pixel & 0xffffffff;
592 dpyinfo->bitmaps[id - 1].stipple_background
593 = f->background_pixel & 0xffffffff;
594 #endif
595
596 dpyinfo->bitmaps[id - 1].file = NULL;
597 dpyinfo->bitmaps[id - 1].height = height;
598 dpyinfo->bitmaps[id - 1].width = width;
599 dpyinfo->bitmaps[id - 1].refcount = 1;
600
601 #ifdef HAVE_X_WINDOWS
602 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
603 dpyinfo->bitmaps[id - 1].have_mask = false;
604 dpyinfo->bitmaps[id - 1].depth = 1;
605 #ifdef USE_CAIRO
606 dpyinfo->bitmaps[id - 1].stipple = NULL;
607 #endif
608 #endif
609
610 #ifdef HAVE_NTGUI
611 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
612 dpyinfo->bitmaps[id - 1].hinst = NULL;
613 dpyinfo->bitmaps[id - 1].depth = 1;
614 #endif
615
616 return id;
617 }
618
619 #if defined HAVE_HAIKU || defined HAVE_NS
620 static char *slurp_file (int, ptrdiff_t *);
621 static Lisp_Object image_find_image_fd (Lisp_Object, int *);
622 static bool xbm_read_bitmap_data (struct frame *, char *, char *,
623 int *, int *, char **, bool);
624 #endif
625
626
627
628 ptrdiff_t
629 image_create_bitmap_from_file (struct frame *f, Lisp_Object file)
630 {
631 #if defined (HAVE_NTGUI)
632 return -1;
633 #else
634 Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
635 #endif
636
637 #ifdef HAVE_NS
638 ptrdiff_t id, size;
639 int fd, width, height, rc;
640 char *contents, *data;
641 void *bitmap;
642
643 if (!STRINGP (image_find_image_fd (file, &fd)))
644 return -1;
645
646 contents = slurp_file (fd, &size);
647
648 if (!contents)
649 return -1;
650
651 rc = xbm_read_bitmap_data (f, contents, contents + size,
652 &width, &height, &data, 0);
653
654 if (!rc)
655 {
656 xfree (contents);
657 return -1;
658 }
659
660 bitmap = ns_image_from_XBM (data, width, height, 0, 0);
661
662 if (!bitmap)
663 {
664 xfree (contents);
665 xfree (data);
666 return -1;
667 }
668
669 id = image_allocate_bitmap_record (f);
670 dpyinfo->bitmaps[id - 1].img = bitmap;
671 dpyinfo->bitmaps[id - 1].refcount = 1;
672 dpyinfo->bitmaps[id - 1].file = xlispstrdup (file);
673 dpyinfo->bitmaps[id - 1].depth = 1;
674 dpyinfo->bitmaps[id - 1].height = ns_image_width (bitmap);
675 dpyinfo->bitmaps[id - 1].width = ns_image_height (bitmap);
676
677 xfree (contents);
678 xfree (data);
679 return id;
680 #endif
681
682 #ifdef HAVE_PGTK
683 GError *err = NULL;
684 ptrdiff_t id;
685 void * bitmap = gdk_pixbuf_new_from_file (SSDATA (file), &err);
686
687 if (!bitmap)
688 {
689 g_error_free (err);
690 return -1;
691 }
692
693 id = image_allocate_bitmap_record (f);
694
695 dpyinfo->bitmaps[id - 1].img = bitmap;
696 dpyinfo->bitmaps[id - 1].refcount = 1;
697 dpyinfo->bitmaps[id - 1].file = xlispstrdup (file);
698 dpyinfo->bitmaps[id - 1].height = gdk_pixbuf_get_width (bitmap);
699 dpyinfo->bitmaps[id - 1].width = gdk_pixbuf_get_height (bitmap);
700 dpyinfo->bitmaps[id - 1].pattern
701 = image_create_pattern_from_pixbuf (f, bitmap);
702 return id;
703 #endif
704
705 #ifdef HAVE_X_WINDOWS
706 unsigned int width, height;
707 Pixmap bitmap;
708 int xhot, yhot, result;
709 ptrdiff_t id;
710 Lisp_Object found;
711 char *filename;
712
713
714 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
715 {
716 if (dpyinfo->bitmaps[id].refcount
717 && dpyinfo->bitmaps[id].file
718 && !strcmp (dpyinfo->bitmaps[id].file, SSDATA (file)))
719 {
720 ++dpyinfo->bitmaps[id].refcount;
721 return id + 1;
722 }
723 }
724
725
726 if (openp (Vx_bitmap_file_path, file, Qnil, &found,
727 make_fixnum (R_OK), false, false)
728 < 0)
729 return -1;
730
731 filename = SSDATA (found);
732
733 result = XReadBitmapFile (FRAME_X_DISPLAY (f),
734 dpyinfo->root_window,
735 filename, &width, &height, &bitmap,
736 &xhot, &yhot);
737 if (result != BitmapSuccess)
738 return -1;
739
740 id = image_allocate_bitmap_record (f);
741 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
742 dpyinfo->bitmaps[id - 1].have_mask = false;
743 dpyinfo->bitmaps[id - 1].refcount = 1;
744 dpyinfo->bitmaps[id - 1].file = xlispstrdup (file);
745 dpyinfo->bitmaps[id - 1].depth = 1;
746 dpyinfo->bitmaps[id - 1].height = height;
747 dpyinfo->bitmaps[id - 1].width = width;
748 #ifdef USE_CAIRO
749 dpyinfo->bitmaps[id - 1].stipple = NULL;
750 #endif
751
752 return id;
753 #endif
754
755 #ifdef HAVE_HAIKU
756 ptrdiff_t id, size;
757 int fd, width, height, rc, bytes_per_line, x, y;
758 char *contents, *data, *tmp;
759 void *bitmap;
760 Lisp_Object found;
761
762
763 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
764 {
765 if (dpyinfo->bitmaps[id].refcount
766 && dpyinfo->bitmaps[id].file
767 && !strcmp (dpyinfo->bitmaps[id].file, SSDATA (file)))
768 {
769 ++dpyinfo->bitmaps[id].refcount;
770 return id + 1;
771 }
772 }
773
774
775 if (openp (Vx_bitmap_file_path, file, Qnil, &found,
776 make_fixnum (R_OK), false, false)
777 < 0)
778 return -1;
779
780 if (!STRINGP (image_find_image_fd (file, &fd))
781 && !STRINGP (image_find_image_fd (found, &fd)))
782 return -1;
783
784 contents = slurp_file (fd, &size);
785
786 if (!contents)
787 return -1;
788
789 rc = xbm_read_bitmap_data (f, contents, contents + size,
790 &width, &height, &data, 0);
791
792 if (!rc)
793 {
794 xfree (contents);
795 return -1;
796 }
797
798 bitmap = BBitmap_new (width, height, false);
799
800 if (!bitmap)
801 {
802 xfree (contents);
803 xfree (data);
804 return -1;
805 }
806
807 id = image_allocate_bitmap_record (f);
808
809 dpyinfo->bitmaps[id - 1].img = bitmap;
810 dpyinfo->bitmaps[id - 1].depth = 1;
811 dpyinfo->bitmaps[id - 1].file = xlispstrdup (file);
812 dpyinfo->bitmaps[id - 1].height = height;
813 dpyinfo->bitmaps[id - 1].width = width;
814 dpyinfo->bitmaps[id - 1].refcount = 1;
815 dpyinfo->bitmaps[id - 1].stipple_foreground
816 = f->foreground_pixel & 0xffffffff;
817 dpyinfo->bitmaps[id - 1].stipple_background
818 = f->background_pixel & 0xffffffff;
819 dpyinfo->bitmaps[id - 1].stipple_bits = data;
820
821 bytes_per_line = (width + 7) / 8;
822 tmp = data;
823
824 for (y = 0; y < height; y++)
825 {
826 for (x = 0; x < width; x++)
827 PUT_PIXEL (bitmap, x, y, ((tmp[x / 8] >> (x % 8)) & 1
828 ? f->foreground_pixel
829 : f->background_pixel));
830
831 tmp += bytes_per_line;
832 }
833
834 xfree (contents);
835 return id;
836 #endif
837 }
838
839
840
841 static void
842 free_bitmap_record (Display_Info *dpyinfo, Bitmap_Record *bm)
843 {
844 #ifdef HAVE_X_WINDOWS
845 XFreePixmap (dpyinfo->display, bm->pixmap);
846 if (bm->have_mask)
847 XFreePixmap (dpyinfo->display, bm->mask);
848 #ifdef USE_CAIRO
849 if (bm->stipple)
850 cairo_pattern_destroy (bm->stipple);
851 #endif
852 #endif
853
854 #ifdef HAVE_NTGUI
855 DeleteObject (bm->pixmap);
856 #endif
857
858 #ifdef HAVE_NS
859 ns_release_object (bm->img);
860 #endif
861
862 #ifdef HAVE_PGTK
863 if (bm->pattern != NULL)
864 cairo_pattern_destroy (bm->pattern);
865 #endif
866
867 #ifdef HAVE_HAIKU
868 BBitmap_free (bm->img);
869
870 if (bm->stipple_bits)
871 xfree (bm->stipple_bits);
872 #endif
873
874 if (bm->file)
875 {
876 xfree (bm->file);
877 bm->file = NULL;
878 }
879 }
880
881
882
883 void
884 image_destroy_bitmap (struct frame *f, ptrdiff_t id)
885 {
886 Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
887
888 if (id > 0)
889 {
890 Bitmap_Record *bm = &dpyinfo->bitmaps[id - 1];
891
892 if (--bm->refcount == 0)
893 {
894 block_input ();
895 free_bitmap_record (dpyinfo, bm);
896 unblock_input ();
897 }
898 }
899 }
900
901
902
903 void
904 image_destroy_all_bitmaps (Display_Info *dpyinfo)
905 {
906 ptrdiff_t i;
907 Bitmap_Record *bm = dpyinfo->bitmaps;
908
909 for (i = 0; i < dpyinfo->bitmaps_last; i++, bm++)
910 if (bm->refcount > 0)
911 free_bitmap_record (dpyinfo, bm);
912
913 dpyinfo->bitmaps_last = 0;
914 }
915
916 #ifndef HAVE_XRENDER
917
918 typedef void Picture;
919 #endif
920
921 static bool image_create_x_image_and_pixmap_1 (struct frame *, int, int, int,
922 Emacs_Pix_Container *,
923 Emacs_Pixmap *, Picture *);
924 static void image_destroy_x_image (Emacs_Pix_Container);
925
926 #ifdef HAVE_NTGUI
927 static HDC image_get_x_image_or_dc (struct frame *, struct image *,
928 bool, HGDIOBJ *);
929 static void image_unget_x_image_or_dc (struct image *, bool,
930 HDC, HGDIOBJ);
931 #else
932 static Emacs_Pix_Container image_get_x_image (struct frame *, struct image *,
933 bool);
934 static void image_unget_x_image (struct image *, bool, Emacs_Pix_Container);
935 #define image_get_x_image_or_dc(f, img, mask_p, dummy) \
936 image_get_x_image (f, img, mask_p)
937 #define image_unget_x_image_or_dc(img, mask_p, ximg, dummy) \
938 image_unget_x_image (img, mask_p, ximg)
939 #endif
940
941 #ifdef HAVE_X_WINDOWS
942
943 #ifndef USE_CAIRO
944 static void image_sync_to_pixmaps (struct frame *, struct image *);
945 #endif
946
947
948
949
950
951 static bool x_create_x_image_and_pixmap (struct frame *, int, int, int,
952 XImage **, Pixmap *);
953 static void x_destroy_x_image (XImage *);
954
955
956
957
958 void
959 x_create_bitmap_mask (struct frame *f, ptrdiff_t id)
960 {
961 Pixmap pixmap, mask;
962 XImage *ximg, *mask_img;
963 unsigned long width, height;
964 bool result;
965 unsigned long bg UNINIT;
966 unsigned long x, y, xp, xm, yp, ym;
967 GC gc;
968
969 Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
970
971 if (!(id > 0))
972 return;
973
974 pixmap = image_bitmap_pixmap (f, id);
975 width = x_bitmap_width (f, id);
976 height = x_bitmap_height (f, id);
977
978 block_input ();
979 ximg = XGetImage (FRAME_X_DISPLAY (f), pixmap, 0, 0, width, height,
980 ~0, ZPixmap);
981
982 if (!ximg)
983 {
984 unblock_input ();
985 return;
986 }
987
988 result = x_create_x_image_and_pixmap (f, width, height, 1, &mask_img, &mask);
989
990 unblock_input ();
991 if (!result)
992 {
993 XDestroyImage (ximg);
994 return;
995 }
996
997 unsigned long corner_pixels[4];
998 corner_pixels[0] = XGetPixel (ximg, 0, 0);
999 corner_pixels[1] = XGetPixel (ximg, width - 1, 0);
1000 corner_pixels[2] = XGetPixel (ximg, width - 1, height - 1);
1001 corner_pixels[3] = XGetPixel (ximg, 0, height - 1);
1002 int i, best_count;
1003 for (i = best_count = 0; i < 4; ++i)
1004 {
1005 int j, n;
1006
1007 for (j = n = 0; j < 4; ++j)
1008 if (corner_pixels[i] == corner_pixels[j])
1009 ++n;
1010
1011 if (n > best_count)
1012 bg = corner_pixels[i], best_count = n;
1013 }
1014
1015 for (y = 0; y < ximg->height; ++y)
1016 {
1017 for (x = 0; x < ximg->width; ++x)
1018 {
1019 xp = x != ximg->width - 1 ? x + 1 : 0;
1020 xm = x != 0 ? x - 1 : ximg->width - 1;
1021 yp = y != ximg->height - 1 ? y + 1 : 0;
1022 ym = y != 0 ? y - 1 : ximg->height - 1;
1023 if (XGetPixel (ximg, x, y) == bg
1024 && XGetPixel (ximg, x, yp) == bg
1025 && XGetPixel (ximg, x, ym) == bg
1026 && XGetPixel (ximg, xp, y) == bg
1027 && XGetPixel (ximg, xp, yp) == bg
1028 && XGetPixel (ximg, xp, ym) == bg
1029 && XGetPixel (ximg, xm, y) == bg
1030 && XGetPixel (ximg, xm, yp) == bg
1031 && XGetPixel (ximg, xm, ym) == bg)
1032 XPutPixel (mask_img, x, y, 0);
1033 else
1034 XPutPixel (mask_img, x, y, 1);
1035 }
1036 }
1037
1038 eassert (input_blocked_p ());
1039 gc = XCreateGC (FRAME_X_DISPLAY (f), mask, 0, NULL);
1040 XPutImage (FRAME_X_DISPLAY (f), mask, gc, mask_img, 0, 0, 0, 0,
1041 width, height);
1042 XFreeGC (FRAME_X_DISPLAY (f), gc);
1043
1044 dpyinfo->bitmaps[id - 1].have_mask = true;
1045 dpyinfo->bitmaps[id - 1].mask = mask;
1046
1047 XDestroyImage (ximg);
1048 x_destroy_x_image (mask_img);
1049 }
1050
1051 #endif
1052
1053
1054
1055
1056
1057
1058
1059
1060 struct image_type
1061 {
1062
1063 int type;
1064
1065
1066
1067 bool (*valid_p) (Lisp_Object spec);
1068
1069
1070
1071 bool (*load_img) (struct frame *f, struct image *img);
1072
1073
1074 void (*free_img) (struct frame *f, struct image *img);
1075
1076 #ifdef WINDOWSNT
1077
1078
1079 bool (*init) (void);
1080
1081 #endif
1082 #if defined HAVE_RSVG || defined HAVE_PNG || defined HAVE_GIF || \
1083 defined HAVE_TIFF || defined HAVE_JPEG || defined HAVE_XPM || \
1084 defined HAVE_NS || defined HAVE_HAIKU || defined HAVE_PGTK || \
1085 defined HAVE_WEBP
1086 # ifdef WINDOWSNT
1087 # define IMAGE_TYPE_INIT(f) f
1088 # else
1089 # define IMAGE_TYPE_INIT(f)
1090 # endif
1091 #endif
1092 };
1093
1094
1095
1096 static struct image_type const *lookup_image_type (Lisp_Object);
1097 static void image_laplace (struct frame *, struct image *);
1098 static void image_emboss (struct frame *, struct image *);
1099 static void image_build_heuristic_mask (struct frame *, struct image *,
1100 Lisp_Object);
1101
1102 static void
1103 add_image_type (Lisp_Object type)
1104 {
1105 Vimage_types = Fcons (type, Vimage_types);
1106 }
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116 bool
1117 valid_image_p (Lisp_Object object)
1118 {
1119 if (IMAGEP (object))
1120 {
1121 Lisp_Object tail = XCDR (object);
1122 FOR_EACH_TAIL_SAFE (tail)
1123 {
1124 if (EQ (XCAR (tail), QCtype))
1125 {
1126 tail = XCDR (tail);
1127 if (CONSP (tail))
1128 {
1129 struct image_type const *type =
1130 lookup_image_type (XCAR (tail));
1131 if (type)
1132 return type->valid_p (object);
1133 }
1134 break;
1135 }
1136 tail = XCDR (tail);
1137 if (! CONSP (tail))
1138 return false;
1139 }
1140 }
1141
1142 return false;
1143 }
1144
1145
1146
1147
1148
1149
1150
1151 static void
1152 image_error (const char *format, ...)
1153 {
1154 va_list ap;
1155 va_start (ap, format);
1156 vadd_to_log (format, ap);
1157 va_end (ap);
1158 }
1159
1160 static void
1161 image_size_error (void)
1162 {
1163 image_error ("Invalid image size (see `max-image-size')");
1164 }
1165
1166
1167
1168
1169
1170
1171 enum image_value_type
1172 {
1173 IMAGE_DONT_CHECK_VALUE_TYPE,
1174 IMAGE_STRING_VALUE,
1175 IMAGE_STRING_OR_NIL_VALUE,
1176 IMAGE_SYMBOL_VALUE,
1177 IMAGE_POSITIVE_INTEGER_VALUE,
1178 IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR,
1179 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
1180 IMAGE_ASCENT_VALUE,
1181 IMAGE_INTEGER_VALUE,
1182 IMAGE_FUNCTION_VALUE,
1183 IMAGE_NUMBER_VALUE,
1184 IMAGE_BOOL_VALUE
1185 };
1186
1187
1188
1189 struct image_keyword
1190 {
1191
1192 const char *name;
1193
1194
1195 enum image_value_type type;
1196
1197
1198 bool mandatory_p;
1199
1200
1201 bool count;
1202
1203
1204 Lisp_Object value;
1205 };
1206
1207
1208
1209
1210
1211
1212
1213
1214 static bool
1215 parse_image_spec (Lisp_Object spec, struct image_keyword *keywords,
1216 int nkeywords, Lisp_Object type)
1217 {
1218 int i;
1219 Lisp_Object plist;
1220
1221 if (!IMAGEP (spec))
1222 return false;
1223
1224 plist = XCDR (spec);
1225 FOR_EACH_TAIL_SAFE (plist)
1226 {
1227 Lisp_Object key, value;
1228
1229
1230 key = XCAR (plist);
1231 plist = XCDR (plist);
1232 if (!SYMBOLP (key))
1233 return false;
1234
1235
1236 if (!CONSP (plist))
1237 return false;
1238 value = XCAR (plist);
1239
1240
1241 for (i = 0; i < nkeywords; ++i)
1242 if (strcmp (keywords[i].name, SSDATA (SYMBOL_NAME (key))) == 0)
1243 break;
1244
1245 if (i == nkeywords)
1246 goto maybe_done;
1247
1248
1249
1250 keywords[i].value = value;
1251 if (keywords[i].count)
1252 return false;
1253 keywords[i].count = true;
1254
1255
1256 switch (keywords[i].type)
1257 {
1258 case IMAGE_STRING_VALUE:
1259 if (!STRINGP (value))
1260 return false;
1261 break;
1262
1263 case IMAGE_STRING_OR_NIL_VALUE:
1264 if (!STRINGP (value) && !NILP (value))
1265 return false;
1266 break;
1267
1268 case IMAGE_SYMBOL_VALUE:
1269 if (!SYMBOLP (value))
1270 return false;
1271 break;
1272
1273 case IMAGE_POSITIVE_INTEGER_VALUE:
1274 if (! RANGED_FIXNUMP (1, value, INT_MAX))
1275 return false;
1276 break;
1277
1278 case IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR:
1279 if (RANGED_FIXNUMP (0, value, INT_MAX))
1280 break;
1281 if (CONSP (value)
1282 && RANGED_FIXNUMP (0, XCAR (value), INT_MAX)
1283 && RANGED_FIXNUMP (0, XCDR (value), INT_MAX))
1284 break;
1285 return false;
1286
1287 case IMAGE_ASCENT_VALUE:
1288 if (SYMBOLP (value) && EQ (value, Qcenter))
1289 break;
1290 else if (RANGED_FIXNUMP (0, value, 100))
1291 break;
1292 return false;
1293
1294 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
1295
1296
1297
1298 if (!FIXNUMP (value) || XFIXNUM (value) < 0)
1299 return false;
1300 break;
1301
1302 case IMAGE_DONT_CHECK_VALUE_TYPE:
1303 break;
1304
1305 case IMAGE_FUNCTION_VALUE:
1306 value = indirect_function (value);
1307 if (FUNCTIONP (value))
1308 break;
1309 return false;
1310
1311 case IMAGE_NUMBER_VALUE:
1312 if (! NUMBERP (value))
1313 return false;
1314 break;
1315
1316 case IMAGE_INTEGER_VALUE:
1317 if (! TYPE_RANGED_FIXNUMP (int, value))
1318 return false;
1319 break;
1320
1321 case IMAGE_BOOL_VALUE:
1322 if (!NILP (value) && !EQ (value, Qt))
1323 return false;
1324 break;
1325
1326 default:
1327 emacs_abort ();
1328 break;
1329 }
1330
1331 if (EQ (key, QCtype)
1332 && !(EQ (type, value) || EQ (type, Qnative_image)))
1333 return false;
1334
1335 maybe_done:
1336 if (NILP (XCDR (plist)))
1337 {
1338
1339 for (i = 0; i < nkeywords; ++i)
1340 if (keywords[i].mandatory_p && keywords[i].count == 0)
1341 return false;
1342
1343 return true;
1344 }
1345 }
1346
1347 return false;
1348 }
1349
1350
1351
1352
1353
1354
1355 static Lisp_Object
1356 image_spec_value (Lisp_Object spec, Lisp_Object key, bool *found)
1357 {
1358 Lisp_Object tail;
1359
1360 eassert (valid_image_p (spec));
1361
1362 tail = XCDR (spec);
1363 FOR_EACH_TAIL_SAFE (tail)
1364 {
1365 if (EQ (XCAR (tail), key))
1366 {
1367 if (found)
1368 *found = 1;
1369 return XCAR (XCDR (tail));
1370 }
1371 tail = XCDR (tail);
1372 if (! CONSP (tail))
1373 break;
1374 }
1375
1376 if (found)
1377 *found = 0;
1378 return Qnil;
1379 }
1380
1381
1382 DEFUN ("image-size", Fimage_size, Simage_size, 1, 3, 0,
1383 doc:
1384
1385
1386
1387
1388
1389
1390
1391
1392 )
1393 (Lisp_Object spec, Lisp_Object pixels, Lisp_Object frame)
1394 {
1395 Lisp_Object size;
1396
1397 size = Qnil;
1398 if (valid_image_p (spec))
1399 {
1400 struct frame *f = decode_window_system_frame (frame);
1401 ptrdiff_t id = lookup_image (f, spec, -1);
1402 struct image *img = IMAGE_FROM_ID (f, id);
1403 int width = img->width + 2 * img->hmargin;
1404 int height = img->height + 2 * img->vmargin;
1405
1406 if (NILP (pixels))
1407 size = Fcons (make_float ((double) width / FRAME_COLUMN_WIDTH (f)),
1408 make_float ((double) height / FRAME_LINE_HEIGHT (f)));
1409 else
1410 size = Fcons (make_fixnum (width), make_fixnum (height));
1411 }
1412 else
1413 error ("Invalid image specification");
1414
1415 return size;
1416 }
1417
1418
1419 DEFUN ("image-mask-p", Fimage_mask_p, Simage_mask_p, 1, 2, 0,
1420 doc:
1421
1422 )
1423 (Lisp_Object spec, Lisp_Object frame)
1424 {
1425 Lisp_Object mask;
1426
1427 mask = Qnil;
1428 if (valid_image_p (spec))
1429 {
1430 struct frame *f = decode_window_system_frame (frame);
1431 ptrdiff_t id = lookup_image (f, spec, -1);
1432 struct image *img = IMAGE_FROM_ID (f, id);
1433 if (img->mask)
1434 mask = Qt;
1435 }
1436 else
1437 error ("Invalid image specification");
1438
1439 return mask;
1440 }
1441
1442 DEFUN ("image-metadata", Fimage_metadata, Simage_metadata, 1, 2, 0,
1443 doc:
1444
1445 )
1446 (Lisp_Object spec, Lisp_Object frame)
1447 {
1448 Lisp_Object ext;
1449
1450 ext = Qnil;
1451 if (valid_image_p (spec))
1452 {
1453 struct frame *f = decode_window_system_frame (frame);
1454 ptrdiff_t id = lookup_image (f, spec, -1);
1455 struct image *img = IMAGE_FROM_ID (f, id);
1456 ext = img->lisp_data;
1457 }
1458
1459 return ext;
1460 }
1461
1462
1463
1464
1465
1466
1467 #define MAX_IMAGE_SIZE 10.0
1468
1469
1470
1471 static struct image *
1472 make_image (Lisp_Object spec, EMACS_UINT hash)
1473 {
1474 struct image *img = xzalloc (sizeof *img);
1475 Lisp_Object file = image_spec_value (spec, QCfile, NULL);
1476
1477 eassert (valid_image_p (spec));
1478 img->dependencies = NILP (file) ? Qnil : list1 (file);
1479 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
1480 eassert (img->type != NULL);
1481 img->spec = spec;
1482 img->lisp_data = Qnil;
1483 img->ascent = DEFAULT_IMAGE_ASCENT;
1484 img->hash = hash;
1485 img->corners[BOT_CORNER] = -1;
1486 return img;
1487 }
1488
1489
1490
1491
1492 static void
1493 free_image (struct frame *f, struct image *img)
1494 {
1495 if (img)
1496 {
1497 struct image_cache *c = FRAME_IMAGE_CACHE (f);
1498
1499
1500 if (img->prev)
1501 img->prev->next = img->next;
1502 else
1503 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
1504
1505 if (img->next)
1506 img->next->prev = img->prev;
1507
1508 c->images[img->id] = NULL;
1509
1510 #if !defined USE_CAIRO && defined HAVE_XRENDER
1511 if (img->picture)
1512 XRenderFreePicture (FRAME_X_DISPLAY (f), img->picture);
1513 if (img->mask_picture)
1514 XRenderFreePicture (FRAME_X_DISPLAY (f), img->mask_picture);
1515 #endif
1516
1517
1518 img->type->free_img (f, img);
1519 xfree (img->face_font_family);
1520 xfree (img);
1521 }
1522 }
1523
1524
1525
1526 static bool
1527 check_image_size (struct frame *f, int width, int height)
1528 {
1529 int w, h;
1530
1531 if (width <= 0 || height <= 0)
1532 return 0;
1533
1534 if (FIXNUMP (Vmax_image_size))
1535 return (width <= XFIXNUM (Vmax_image_size)
1536 && height <= XFIXNUM (Vmax_image_size));
1537 else if (FLOATP (Vmax_image_size))
1538 {
1539 if (f != NULL)
1540 {
1541 w = FRAME_PIXEL_WIDTH (f);
1542 h = FRAME_PIXEL_HEIGHT (f);
1543 }
1544 else
1545 w = h = 1024;
1546 return (width <= XFLOAT_DATA (Vmax_image_size) * w
1547 && height <= XFLOAT_DATA (Vmax_image_size) * h);
1548 }
1549 else
1550 return 1;
1551 }
1552
1553
1554
1555
1556 void
1557 prepare_image_for_display (struct frame *f, struct image *img)
1558 {
1559
1560 img->timestamp = current_timespec ();
1561
1562
1563
1564 if (img->pixmap == NO_PIXMAP && !img->load_failed_p)
1565 img->load_failed_p = ! img->type->load_img (f, img);
1566
1567 #ifdef USE_CAIRO
1568 if (!img->load_failed_p)
1569 {
1570 block_input ();
1571 if (img->cr_data == NULL || (cairo_pattern_get_type (img->cr_data)
1572 != CAIRO_PATTERN_TYPE_SURFACE))
1573 {
1574
1575
1576 IMAGE_BACKGROUND (img, f, img->pixmap);
1577 IMAGE_BACKGROUND_TRANSPARENT (img, f, img->mask);
1578 cr_put_image_to_cr_data (img);
1579 if (img->cr_data == NULL)
1580 {
1581 img->load_failed_p = 1;
1582 img->type->free_img (f, img);
1583 }
1584 }
1585 unblock_input ();
1586 }
1587 #elif defined HAVE_X_WINDOWS
1588 if (!img->load_failed_p)
1589 {
1590 block_input ();
1591 image_sync_to_pixmaps (f, img);
1592 unblock_input ();
1593 }
1594 #endif
1595 }
1596
1597
1598
1599
1600
1601 int
1602 image_ascent (struct image *img, struct face *face, struct glyph_slice *slice)
1603 {
1604 int height;
1605 int ascent;
1606
1607 if (slice->height == img->height)
1608 height = img->height + img->vmargin;
1609 else if (slice->y == 0)
1610 height = slice->height + img->vmargin;
1611 else
1612 height = slice->height;
1613
1614 if (img->ascent == CENTERED_IMAGE_ASCENT)
1615 {
1616 if (face->font)
1617 {
1618 #ifdef HAVE_NTGUI
1619
1620 ascent = height / 2 - (FONT_DESCENT (face->font)
1621 - FONT_BASE (face->font)) / 2;
1622 #else
1623
1624
1625
1626
1627
1628 ascent = (height + FONT_BASE (face->font)
1629 - FONT_DESCENT (face->font) + 1) / 2;
1630 #endif
1631 }
1632 else
1633 ascent = height / 2;
1634 }
1635 else
1636 ascent = height * (img->ascent / 100.0);
1637
1638 return ascent;
1639 }
1640
1641
1642
1643
1644
1645
1646
1647 static RGB_PIXEL_COLOR
1648 four_corners_best (Emacs_Pix_Context pimg, int *corners,
1649 unsigned long width, unsigned long height)
1650 {
1651 RGB_PIXEL_COLOR corner_pixels[4];
1652 RGB_PIXEL_COLOR best UNINIT;
1653 int i, best_count;
1654
1655 if (corners && corners[BOT_CORNER] >= 0)
1656 {
1657
1658 corner_pixels[0] = GET_PIXEL (pimg, corners[LEFT_CORNER], corners[TOP_CORNER]);
1659 corner_pixels[1] = GET_PIXEL (pimg, corners[RIGHT_CORNER] - 1, corners[TOP_CORNER]);
1660 corner_pixels[2] = GET_PIXEL (pimg, corners[RIGHT_CORNER] - 1, corners[BOT_CORNER] - 1);
1661 corner_pixels[3] = GET_PIXEL (pimg, corners[LEFT_CORNER], corners[BOT_CORNER] - 1);
1662 }
1663 else
1664
1665 {
1666
1667 corner_pixels[0] = GET_PIXEL (pimg, 0, 0);
1668 corner_pixels[1] = GET_PIXEL (pimg, width - 1, 0);
1669 corner_pixels[2] = GET_PIXEL (pimg, width - 1, height - 1);
1670 corner_pixels[3] = GET_PIXEL (pimg, 0, height - 1);
1671 }
1672
1673 for (i = best_count = 0; i < 4; ++i)
1674 {
1675 int j, n;
1676
1677 for (j = n = 0; j < 4; ++j)
1678 if (corner_pixels[i] == corner_pixels[j])
1679 ++n;
1680
1681 if (n > best_count)
1682 best = corner_pixels[i], best_count = n;
1683 }
1684
1685 return best;
1686 }
1687
1688
1689
1690
1691
1692
1693 RGB_PIXEL_COLOR
1694 image_background (struct image *img, struct frame *f, Emacs_Pix_Context pimg)
1695 {
1696 if (! img->background_valid)
1697
1698 {
1699 bool free_pimg = !pimg;
1700 #ifdef HAVE_NTGUI
1701 HGDIOBJ prev;
1702 #endif
1703
1704 if (free_pimg)
1705 pimg = image_get_x_image_or_dc (f, img, 0, &prev);
1706
1707 RGB_PIXEL_COLOR bg
1708 = four_corners_best (pimg, img->corners, img->width, img->height);
1709 #ifdef USE_CAIRO
1710 {
1711 char color_name[30];
1712 sprintf (color_name, "#%04x%04x%04x",
1713 (unsigned int) RED16_FROM_ULONG (bg),
1714 (unsigned int) GREEN16_FROM_ULONG (bg),
1715 (unsigned int) BLUE16_FROM_ULONG (bg));
1716 bg = image_alloc_image_color (f, img, build_string (color_name), 0);
1717 }
1718 #endif
1719 img->background = bg;
1720
1721 if (free_pimg)
1722 image_unget_x_image_or_dc (img, 0, pimg, prev);
1723
1724 img->background_valid = 1;
1725 }
1726
1727 return img->background;
1728 }
1729
1730
1731
1732
1733
1734
1735 int
1736 image_background_transparent (struct image *img, struct frame *f,
1737 Emacs_Pix_Context mask)
1738 {
1739 if (! img->background_transparent_valid)
1740
1741 {
1742 if (img->mask)
1743 {
1744 bool free_mask = !mask;
1745 #ifdef HAVE_NTGUI
1746 HGDIOBJ prev;
1747 #endif
1748
1749 if (free_mask)
1750 mask = image_get_x_image_or_dc (f, img, 1, &prev);
1751
1752 img->background_transparent
1753 = (four_corners_best (mask, img->corners, img->width, img->height) == PIX_MASK_RETAIN);
1754
1755 if (free_mask)
1756 image_unget_x_image_or_dc (img, 1, mask, prev);
1757 }
1758 else
1759 img->background_transparent = 0;
1760
1761 img->background_transparent_valid = 1;
1762 }
1763
1764 return img->background_transparent;
1765 }
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778 #define CLEAR_IMAGE_PIXMAP (1 << 0)
1779 #define CLEAR_IMAGE_MASK (1 << 1)
1780 #define CLEAR_IMAGE_COLORS (1 << 2)
1781
1782 static void
1783 image_clear_image_1 (struct frame *f, struct image *img, int flags)
1784 {
1785 if (flags & CLEAR_IMAGE_PIXMAP)
1786 {
1787 if (img->pixmap)
1788 {
1789 FRAME_TERMINAL (f)->free_pixmap (f, img->pixmap);
1790 img->pixmap = NO_PIXMAP;
1791
1792 img->background_valid = 0;
1793 }
1794 #if defined HAVE_X_WINDOWS && !defined USE_CAIRO
1795 if (img->ximg)
1796 {
1797 image_destroy_x_image (img->ximg);
1798 img->ximg = NULL;
1799 img->background_valid = 0;
1800 }
1801 #endif
1802 }
1803
1804 if (flags & CLEAR_IMAGE_MASK)
1805 {
1806 if (img->mask)
1807 {
1808 FRAME_TERMINAL (f)->free_pixmap (f, img->mask);
1809 img->mask = NO_PIXMAP;
1810 img->background_transparent_valid = 0;
1811 }
1812 #if defined HAVE_X_WINDOWS && !defined USE_CAIRO
1813 if (img->mask_img)
1814 {
1815 image_destroy_x_image (img->mask_img);
1816 img->mask_img = NULL;
1817 img->background_transparent_valid = 0;
1818 }
1819 #endif
1820 }
1821
1822 if ((flags & CLEAR_IMAGE_COLORS) && img->ncolors)
1823 {
1824
1825 #if defined HAVE_X_WINDOWS && !defined USE_CAIRO
1826 x_free_colors (f, img->colors, img->ncolors);
1827 #endif
1828 xfree (img->colors);
1829 img->colors = NULL;
1830 img->ncolors = 0;
1831 }
1832
1833 #ifdef USE_CAIRO
1834 if (img->cr_data)
1835 {
1836 cairo_pattern_destroy (img->cr_data);
1837 img->cr_data = NULL;
1838 }
1839 #endif
1840 }
1841
1842
1843
1844 static void
1845 image_clear_image (struct frame *f, struct image *img)
1846 {
1847 block_input ();
1848 image_clear_image_1 (f, img,
1849 (CLEAR_IMAGE_PIXMAP
1850 | CLEAR_IMAGE_MASK
1851 | CLEAR_IMAGE_COLORS));
1852 unblock_input ();
1853 }
1854
1855
1856
1857
1858
1859
1860
1861 static unsigned long
1862 image_alloc_image_color (struct frame *f, struct image *img,
1863 Lisp_Object color_name, unsigned long dflt)
1864 {
1865 Emacs_Color color;
1866 unsigned long result;
1867
1868 eassert (STRINGP (color_name));
1869
1870 if (FRAME_TERMINAL (f)->defined_color_hook (f,
1871 SSDATA (color_name),
1872 &color,
1873 true,
1874 false)
1875 && img->ncolors < min (min (PTRDIFF_MAX, SIZE_MAX) / sizeof *img->colors,
1876 INT_MAX))
1877 {
1878
1879
1880 ptrdiff_t ncolors = img->ncolors + 1;
1881 img->colors = xrealloc (img->colors, ncolors * sizeof *img->colors);
1882 img->colors[ncolors - 1] = color.pixel;
1883 img->ncolors = ncolors;
1884 result = color.pixel;
1885 }
1886 else
1887 result = dflt;
1888
1889 return result;
1890 }
1891
1892
1893
1894
1895
1896
1897
1898 static void cache_image (struct frame *f, struct image *img);
1899
1900
1901
1902
1903 struct image_cache *
1904 make_image_cache (void)
1905 {
1906 struct image_cache *c = xmalloc (sizeof *c);
1907
1908 c->size = 50;
1909 c->used = c->refcount = 0;
1910 c->images = xmalloc (c->size * sizeof *c->images);
1911 c->buckets = xzalloc (IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets);
1912 return c;
1913 }
1914
1915
1916
1917 static struct image *
1918 search_image_cache (struct frame *f, Lisp_Object spec, EMACS_UINT hash,
1919 unsigned long foreground, unsigned long background,
1920 int font_size, char *font_family, bool ignore_colors)
1921 {
1922 struct image *img;
1923 struct image_cache *c = FRAME_IMAGE_CACHE (f);
1924 int i = hash % IMAGE_CACHE_BUCKETS_SIZE;
1925
1926 if (!c) return NULL;
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940 for (img = c->buckets[i]; img; img = img->next)
1941 if (img->hash == hash
1942 && !NILP (Fequal (img->spec, spec))
1943 && (ignore_colors || (img->face_foreground == foreground
1944 && img->face_background == background
1945 && img->face_font_size == font_size
1946 && (font_family
1947 &&!strcmp (font_family, img->face_font_family)))))
1948 break;
1949 return img;
1950 }
1951
1952
1953
1954
1955
1956
1957 static Lisp_Object
1958 filter_image_spec (Lisp_Object spec)
1959 {
1960 Lisp_Object out = Qnil;
1961
1962
1963 if (CONSP (spec))
1964 spec = XCDR (spec);
1965
1966 while (CONSP (spec))
1967 {
1968 Lisp_Object key = XCAR (spec);
1969 spec = XCDR (spec);
1970 if (CONSP (spec))
1971 {
1972 Lisp_Object value = XCAR (spec);
1973 spec = XCDR (spec);
1974
1975
1976
1977 if (!(EQ (key, QCanimate_buffer)
1978 || EQ (key, QCanimate_tardiness)
1979 || EQ (key, QCanimate_position)
1980 || EQ (key, QCanimate_multi_frame_data)))
1981 {
1982 out = Fcons (value, out);
1983 out = Fcons (key, out);
1984 }
1985 }
1986 }
1987 return out;
1988 }
1989
1990
1991
1992 static void
1993 uncache_image (struct frame *f, Lisp_Object spec)
1994 {
1995 struct image *img;
1996 EMACS_UINT hash = sxhash (filter_image_spec (spec));
1997
1998
1999
2000
2001
2002 while ((img = search_image_cache (f, spec, hash, 0, 0, 0, NULL, true)))
2003 {
2004 free_image (f, img);
2005
2006
2007 SET_FRAME_GARBAGED (f);
2008 }
2009 }
2010
2011
2012
2013
2014
2015 void
2016 free_image_cache (struct frame *f)
2017 {
2018 struct image_cache *c = FRAME_IMAGE_CACHE (f);
2019 if (c)
2020 {
2021 ptrdiff_t i;
2022
2023
2024 eassert (c->refcount == 0);
2025
2026 for (i = 0; i < c->used; ++i)
2027 free_image (f, c->images[i]);
2028 xfree (c->images);
2029 xfree (c->buckets);
2030 xfree (c);
2031 FRAME_IMAGE_CACHE (f) = NULL;
2032 }
2033 }
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044 static void
2045 clear_image_cache (struct frame *f, Lisp_Object filter)
2046 {
2047 struct image_cache *c = FRAME_IMAGE_CACHE (f);
2048
2049 if (c && !f->inhibit_clear_image_cache)
2050 {
2051 ptrdiff_t i, nfreed = 0;
2052
2053
2054
2055 block_input ();
2056
2057 if (!NILP (filter))
2058 {
2059
2060 for (i = 0; i < c->used; ++i)
2061 {
2062 struct image *img = c->images[i];
2063 if (img && (EQ (Qt, filter)
2064 || !NILP (Fmember (filter, img->dependencies))))
2065 {
2066 free_image (f, img);
2067 ++nfreed;
2068 }
2069 }
2070 }
2071 else if (FIXNUMP (Vimage_cache_eviction_delay))
2072 {
2073
2074 struct timespec old, t;
2075 double delay;
2076 ptrdiff_t nimages = 0;
2077
2078 for (i = 0; i < c->used; ++i)
2079 if (c->images[i])
2080 nimages++;
2081
2082
2083
2084 delay = XFIXNUM (Vimage_cache_eviction_delay);
2085 if (nimages > 40)
2086 delay = 1600 * delay / nimages / nimages;
2087 delay = max (delay, 1);
2088
2089 t = current_timespec ();
2090 old = timespec_sub (t, dtotimespec (delay));
2091
2092 for (i = 0; i < c->used; ++i)
2093 {
2094 struct image *img = c->images[i];
2095 if (img && timespec_cmp (img->timestamp, old) < 0)
2096 {
2097 free_image (f, img);
2098 ++nfreed;
2099 }
2100 }
2101 }
2102
2103
2104
2105
2106
2107 if (nfreed)
2108 {
2109 Lisp_Object tail, frame;
2110
2111 FOR_EACH_FRAME (tail, frame)
2112 {
2113 struct frame *fr = XFRAME (frame);
2114 if (FRAME_IMAGE_CACHE (fr) == c)
2115 clear_current_matrices (fr);
2116 }
2117
2118 windows_or_buffers_changed = 19;
2119 }
2120
2121 unblock_input ();
2122 }
2123 }
2124
2125 void
2126 clear_image_caches (Lisp_Object filter)
2127 {
2128
2129
2130
2131
2132 Lisp_Object tail, frame;
2133 FOR_EACH_FRAME (tail, frame)
2134 if (FRAME_WINDOW_P (XFRAME (frame)))
2135 clear_image_cache (XFRAME (frame), filter);
2136 }
2137
2138 DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
2139 0, 2, 0,
2140 doc:
2141
2142
2143
2144
2145
2146
2147
2148
2149 )
2150 (Lisp_Object filter, Lisp_Object animation_cache)
2151 {
2152 if (!NILP (animation_cache))
2153 {
2154 #if defined (HAVE_WEBP) || defined (HAVE_GIF)
2155 anim_prune_animation_cache (XCDR (animation_cache));
2156 #endif
2157 return Qnil;
2158 }
2159
2160 if (! (NILP (filter) || FRAMEP (filter)))
2161 clear_image_caches (filter);
2162 else
2163 clear_image_cache (decode_window_system_frame (filter), Qt);
2164
2165
2166 image_prune_animation_caches (true);
2167
2168 return Qnil;
2169 }
2170
2171 static size_t
2172 image_size_in_bytes (struct image *img)
2173 {
2174 size_t size = 0;
2175
2176 #if defined USE_CAIRO
2177 Emacs_Pixmap pm = img->pixmap;
2178 if (pm)
2179 size += pm->height * pm->bytes_per_line;
2180 Emacs_Pixmap msk = img->mask;
2181 if (msk)
2182 size += msk->height * msk->bytes_per_line;
2183
2184 #elif defined HAVE_X_WINDOWS
2185
2186
2187 if (img->pixmap != NO_PIXMAP)
2188 size += img->width * img->height * 3;
2189 if (img->mask != NO_PIXMAP)
2190 size += img->width * img->height / 8;
2191
2192 if (img->ximg && img->ximg->data)
2193 size += img->ximg->bytes_per_line * img->ximg->height;
2194 if (img->mask_img && img->mask_img->data)
2195 size += img->mask_img->bytes_per_line * img->mask_img->height;
2196
2197 #elif defined HAVE_NS
2198 if (img->pixmap)
2199 size += ns_image_size_in_bytes (img->pixmap);
2200 if (img->mask)
2201 size += ns_image_size_in_bytes (img->mask);
2202
2203 #elif defined HAVE_NTGUI
2204 if (img->pixmap)
2205 size += w32_image_size (img->pixmap);
2206 if (img->mask)
2207 size += w32_image_size (img->mask);
2208
2209 #elif defined HAVE_HAIKU
2210 if (img->pixmap)
2211 size += BBitmap_bytes_length (img->pixmap);
2212 if (img->mask)
2213 size += BBitmap_bytes_length (img->mask);
2214 #endif
2215
2216 return size;
2217 }
2218
2219 static size_t
2220 image_frame_cache_size (struct frame *f)
2221 {
2222 struct image_cache *c = FRAME_IMAGE_CACHE (f);
2223 if (!c)
2224 return 0;
2225
2226 size_t total = 0;
2227 for (ptrdiff_t i = 0; i < c->used; ++i)
2228 {
2229 struct image *img = c->images[i];
2230 total += img ? image_size_in_bytes (img) : 0;
2231 }
2232 return total;
2233 }
2234
2235 DEFUN ("image-flush", Fimage_flush, Simage_flush,
2236 1, 2, 0,
2237 doc:
2238
2239
2240
2241
2242
2243 )
2244 (Lisp_Object spec, Lisp_Object frame)
2245 {
2246 if (!valid_image_p (spec))
2247 error ("Invalid image specification");
2248
2249 if (EQ (frame, Qt))
2250 {
2251 Lisp_Object tail;
2252 FOR_EACH_FRAME (tail, frame)
2253 {
2254 struct frame *f = XFRAME (frame);
2255 if (FRAME_WINDOW_P (f))
2256 uncache_image (f, spec);
2257 }
2258 }
2259 else
2260 uncache_image (decode_window_system_frame (frame), spec);
2261
2262 return Qnil;
2263 }
2264
2265
2266
2267
2268
2269 static void
2270 postprocess_image (struct frame *f, struct image *img)
2271 {
2272
2273 if (img->pixmap)
2274 {
2275 Lisp_Object conversion, spec;
2276 Lisp_Object mask;
2277
2278 spec = img->spec;
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290 mask = image_spec_value (spec, QCheuristic_mask, NULL);
2291 if (!NILP (mask))
2292 image_build_heuristic_mask (f, img, mask);
2293 else
2294 {
2295 bool found_p;
2296
2297 mask = image_spec_value (spec, QCmask, &found_p);
2298
2299 if (EQ (mask, Qheuristic))
2300 image_build_heuristic_mask (f, img, Qt);
2301 else if (CONSP (mask)
2302 && EQ (XCAR (mask), Qheuristic))
2303 {
2304 if (CONSP (XCDR (mask)))
2305 image_build_heuristic_mask (f, img, XCAR (XCDR (mask)));
2306 else
2307 image_build_heuristic_mask (f, img, XCDR (mask));
2308 }
2309 else if (NILP (mask) && found_p && img->mask)
2310 image_clear_image_1 (f, img, CLEAR_IMAGE_MASK);
2311 }
2312
2313
2314
2315 conversion = image_spec_value (spec, QCconversion, NULL);
2316 if (EQ (conversion, Qdisabled))
2317 image_disable_image (f, img);
2318 else if (EQ (conversion, Qlaplace))
2319 image_laplace (f, img);
2320 else if (EQ (conversion, Qemboss))
2321 image_emboss (f, img);
2322 else if (CONSP (conversion)
2323 && EQ (XCAR (conversion), Qedge_detection))
2324 {
2325 Lisp_Object tem;
2326 tem = XCDR (conversion);
2327 if (CONSP (tem))
2328 image_edge_detection (f, img,
2329 plist_get (tem, QCmatrix),
2330 plist_get (tem, QCcolor_adjustment));
2331 }
2332 }
2333 }
2334
2335 #if defined (HAVE_IMAGEMAGICK) || defined (HAVE_NATIVE_TRANSFORMS)
2336
2337
2338
2339 static int
2340 scale_image_size (int size, double divisor, double multiplier)
2341 {
2342 if (divisor != 0)
2343 {
2344 double scaled = size * multiplier / divisor;
2345 if (scaled < INT_MAX)
2346 {
2347
2348 return ceil (scaled);
2349 }
2350 }
2351 return INT_MAX;
2352 }
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362 static int
2363 image_get_dimension (struct image *img, Lisp_Object symbol)
2364 {
2365 Lisp_Object value = image_spec_value (img->spec, symbol, NULL);
2366
2367 if (FIXNATP (value))
2368 return min (XFIXNAT (value), INT_MAX);
2369 if (CONSP (value) && NUMBERP (CAR (value)) && EQ (Qem, CDR (value)))
2370 return scale_image_size (img->face_font_size, 1, XFLOATINT (CAR (value)));
2371
2372 return -1;
2373 }
2374
2375
2376
2377
2378 static void
2379 compute_image_size (double width, double height,
2380 struct image *img,
2381 int *d_width, int *d_height)
2382 {
2383 double scale = 1;
2384 Lisp_Object value = image_spec_value (img->spec, QCscale, NULL);
2385 if (NUMBERP (value))
2386 {
2387 double dval = XFLOATINT (value);
2388 if (0 <= dval)
2389 scale = dval;
2390 }
2391
2392
2393
2394
2395
2396 int desired_width = image_get_dimension (img, QCwidth), max_width;
2397 if (desired_width < 0)
2398 max_width = image_get_dimension (img, QCmax_width);
2399 else
2400 {
2401 desired_width = scale_image_size (desired_width, 1, scale);
2402
2403 max_width = -1;
2404 }
2405
2406 int desired_height = image_get_dimension (img, QCheight), max_height;
2407 if (desired_height < 0)
2408 max_height = image_get_dimension (img, QCmax_height);
2409 else
2410 {
2411 desired_height = scale_image_size (desired_height, 1, scale);
2412
2413 max_height = -1;
2414 }
2415
2416
2417
2418 if (0 <= desired_width && 0 <= desired_height)
2419 goto out;
2420
2421 if (0 <= desired_width)
2422
2423 desired_height = scale_image_size (desired_width, width, height);
2424 else if (0 <= desired_height)
2425
2426 desired_width = scale_image_size (desired_height, height, width);
2427 else
2428 {
2429 desired_width = scale_image_size (width, 1, scale);
2430 desired_height = scale_image_size (height, 1, scale);
2431 }
2432
2433 if (0 <= max_width && max_width < desired_width)
2434 {
2435
2436 desired_width = max_width;
2437 desired_height = scale_image_size (desired_width, width, height);
2438 }
2439
2440 if (0 <= max_height && max_height < desired_height)
2441 {
2442
2443 desired_height = max_height;
2444 desired_width = scale_image_size (desired_height, height, width);
2445 }
2446
2447 out:
2448 *d_width = desired_width;
2449 *d_height = desired_height;
2450 }
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534 typedef double matrix3x3[3][3];
2535
2536 static void
2537 matrix3x3_mult (matrix3x3 a, matrix3x3 b, matrix3x3 result)
2538 {
2539 for (int i = 0; i < 3; i++)
2540 for (int j = 0; j < 3; j++)
2541 {
2542 double sum = 0;
2543 for (int k = 0; k < 3; k++)
2544 sum += a[i][k] * b[k][j];
2545 result[i][j] = sum;
2546 }
2547 }
2548
2549 static void
2550 compute_image_rotation (struct image *img, double *rotation)
2551 {
2552 bool foundp = false;
2553 Lisp_Object value = image_spec_value (img->spec, QCrotation, &foundp);
2554 if (!foundp)
2555 return;
2556 if (! NUMBERP (value))
2557 {
2558 image_error ("Invalid image `:rotation' parameter");
2559 return;
2560 }
2561
2562 Lisp_Object reduced_angle = Fmod (value, make_fixnum (360));
2563 if (FLOATP (reduced_angle))
2564 *rotation = XFLOAT_DATA (reduced_angle);
2565 else
2566 *rotation = XFIXNUM (reduced_angle);
2567 }
2568
2569 static void
2570 image_set_transform (struct frame *f, struct image *img)
2571 {
2572 bool flip;
2573
2574 #if defined HAVE_HAIKU
2575 matrix3x3 identity = {
2576 { 1, 0, 0 },
2577 { 0, 1, 0 },
2578 { 0, 0, 1 },
2579 };
2580
2581 img->original_width = img->width;
2582 img->original_height = img->height;
2583 img->use_bilinear_filtering = false;
2584
2585 memcpy (&img->transform, identity, sizeof identity);
2586 #endif
2587
2588 # if (defined HAVE_IMAGEMAGICK \
2589 && !defined DONT_CREATE_TRANSFORMED_IMAGEMAGICK_IMAGE)
2590
2591 if (EQ (image_spec_value (img->spec, QCtype, NULL), Qimagemagick))
2592 return;
2593 # endif
2594
2595 # if !defined USE_CAIRO && defined HAVE_XRENDER
2596 if (!img->picture)
2597 return;
2598
2599
2600 img->original_width = img->width;
2601 img->original_height = img->height;
2602 # endif
2603
2604
2605 int width, height;
2606
2607 #ifdef HAVE_RSVG
2608
2609 if (EQ (image_spec_value (img->spec, QCtype, NULL), Qsvg))
2610 {
2611 width = img->width / FRAME_SCALE_FACTOR (f);
2612 height = img->height / FRAME_SCALE_FACTOR (f);
2613 }
2614 else
2615 #endif
2616 compute_image_size (img->width, img->height, img, &width, &height);
2617
2618
2619 double rotation = 0.0;
2620 compute_image_rotation (img, &rotation);
2621
2622
2623 flip = !NILP (image_spec_value (img->spec, QCflip, NULL));
2624
2625 # if defined USE_CAIRO || defined HAVE_XRENDER || defined HAVE_NS || defined HAVE_HAIKU
2626
2627
2628
2629
2630
2631 bool smoothing;
2632 Lisp_Object s = image_spec_value (img->spec, QCtransform_smoothing, NULL);
2633 if (NILP (s))
2634 smoothing = (width < img->width) || (height < img->height);
2635 else
2636 smoothing = !NILP (s);
2637 # endif
2638
2639 #ifdef HAVE_HAIKU
2640 img->use_bilinear_filtering = smoothing;
2641 #endif
2642
2643
2644
2645 matrix3x3 matrix
2646 = {
2647 # if defined USE_CAIRO || defined HAVE_XRENDER
2648 [0][0] = (!IEEE_FLOATING_POINT && width == 0 ? DBL_MAX
2649 : img->width / (double) width),
2650 [1][1] = (!IEEE_FLOATING_POINT && height == 0 ? DBL_MAX
2651 : img->height / (double) height),
2652 # elif defined HAVE_NTGUI || defined HAVE_NS || defined HAVE_HAIKU
2653 [0][0] = (!IEEE_FLOATING_POINT && img->width == 0 ? DBL_MAX
2654 : width / (double) img->width),
2655 [1][1] = (!IEEE_FLOATING_POINT && img->height == 0 ? DBL_MAX
2656 : height / (double) img->height),
2657 # else
2658 [0][0] = 1, [1][1] = 1,
2659 # endif
2660 [2][2] = 1 };
2661 img->width = width;
2662 img->height = height;
2663
2664
2665
2666 int rotate_flag = -1;
2667
2668
2669
2670 #ifdef HAVE_HAIKU
2671 int extra_tx, extra_ty;
2672
2673 extra_tx = 0;
2674 extra_ty = 0;
2675 #endif
2676
2677 if (rotation == 0 && !flip)
2678 rotate_flag = 0;
2679 else
2680 {
2681 # if (defined USE_CAIRO || defined HAVE_XRENDER \
2682 || defined HAVE_NTGUI || defined HAVE_NS \
2683 || defined HAVE_HAIKU)
2684 int cos_r, sin_r;
2685 if (rotation == 0)
2686 {
2687
2688
2689
2690
2691
2692 cos_r = 1;
2693 sin_r = 0;
2694 rotate_flag = 1;
2695
2696 #ifdef HAVE_HAIKU
2697 extra_tx = width;
2698 extra_ty = 0;
2699 #endif
2700 }
2701 else if (rotation == 90)
2702 {
2703 width = img->height;
2704 height = img->width;
2705 cos_r = 0;
2706 sin_r = 1;
2707 rotate_flag = 1;
2708
2709 #ifdef HAVE_HAIKU
2710 if (!flip)
2711 extra_ty = height;
2712 extra_tx = 0;
2713 #endif
2714 }
2715 else if (rotation == 180)
2716 {
2717 cos_r = -1;
2718 sin_r = 0;
2719 rotate_flag = 1;
2720
2721 #ifdef HAVE_HAIKU
2722 if (!flip)
2723 extra_tx = width;
2724 extra_ty = height;
2725 #endif
2726 }
2727 else if (rotation == 270)
2728 {
2729 width = img->height;
2730 height = img->width;
2731 cos_r = 0;
2732 sin_r = -1;
2733 rotate_flag = 1;
2734
2735 #ifdef HAVE_HAIKU
2736 extra_tx = width;
2737
2738 if (flip)
2739 extra_ty = height;
2740 #endif
2741 }
2742
2743 if (0 < rotate_flag)
2744 {
2745 # if defined USE_CAIRO || defined HAVE_XRENDER
2746
2747 matrix3x3 t
2748 = { [0][0] = 1,
2749 [1][1] = 1,
2750 [2][0] = img->width*.5, [2][1] = img->height*.5, [2][2] = 1 };
2751 matrix3x3 u;
2752 matrix3x3_mult (t, matrix, u);
2753
2754
2755 matrix3x3 rot = { [0][0] = cos_r, [0][1] = -sin_r,
2756 [1][0] = sin_r, [1][1] = cos_r,
2757 [2][2] = 1 };
2758 matrix3x3 v;
2759 matrix3x3_mult (rot, u, v);
2760
2761
2762 t[2][0] = width * -.5;
2763 t[2][1] = height * -.5;
2764 if (flip)
2765 {
2766 t[0][0] = -t[0][0];
2767 t[2][0] = -t[2][0];
2768 }
2769 matrix3x3_mult (t, v, matrix);
2770 # else
2771
2772 matrix3x3 t
2773 = { [0][0] = 1,
2774 [1][1] = 1,
2775 [2][0] = img->width*-.5, [2][1] = img->height*-.5, [2][2] = 1 };
2776 matrix3x3 u;
2777 matrix3x3_mult (matrix, t, u);
2778
2779
2780 matrix3x3 rot = { [0][0] = cos_r, [0][1] = sin_r,
2781 [1][0] = -sin_r, [1][1] = cos_r,
2782 [2][2] = 1 };
2783 matrix3x3 v;
2784 matrix3x3_mult (u, rot, v);
2785
2786
2787 t[2][0] = width * .5;
2788 t[2][1] = height * .5;
2789 if (flip) t[0][0] = -t[0][0];
2790 matrix3x3_mult (v, t, matrix);
2791 # endif
2792 img->width = width;
2793 img->height = height;
2794 }
2795 # endif
2796 }
2797
2798 if (rotate_flag < 0)
2799 image_error ("No native support for rotation by %g degrees",
2800 make_float (rotation));
2801
2802 # if defined (HAVE_NS)
2803
2804
2805 ns_image_set_transform (img->pixmap, matrix);
2806 ns_image_set_smoothing (img->pixmap, smoothing);
2807 # elif defined USE_CAIRO
2808 cairo_matrix_t cr_matrix = {matrix[0][0], matrix[0][1], matrix[1][0],
2809 matrix[1][1], matrix[2][0], matrix[2][1]};
2810 cairo_pattern_t *pattern = cairo_pattern_create_rgb (0, 0, 0);
2811 cairo_pattern_set_matrix (pattern, &cr_matrix);
2812 cairo_pattern_set_filter (pattern, smoothing
2813 ? CAIRO_FILTER_BEST : CAIRO_FILTER_NEAREST);
2814
2815 img->cr_data = pattern;
2816 # elif defined (HAVE_XRENDER)
2817 if (img->picture)
2818 {
2819 XTransform tmat
2820 = {{{XDoubleToFixed (matrix[0][0]),
2821 XDoubleToFixed (matrix[1][0]),
2822 XDoubleToFixed (matrix[2][0])},
2823 {XDoubleToFixed (matrix[0][1]),
2824 XDoubleToFixed (matrix[1][1]),
2825 XDoubleToFixed (matrix[2][1])},
2826 {XDoubleToFixed (matrix[0][2]),
2827 XDoubleToFixed (matrix[1][2]),
2828 XDoubleToFixed (matrix[2][2])}}};
2829
2830 XRenderSetPictureFilter (FRAME_X_DISPLAY (f), img->picture,
2831 smoothing ? FilterBest : FilterNearest, 0, 0);
2832 XRenderSetPictureTransform (FRAME_X_DISPLAY (f), img->picture, &tmat);
2833
2834 if (img->mask_picture)
2835 {
2836 XRenderSetPictureFilter (FRAME_X_DISPLAY (f), img->mask_picture,
2837 smoothing ? FilterBest : FilterNearest, 0, 0);
2838 XRenderSetPictureTransform (FRAME_X_DISPLAY (f), img->mask_picture,
2839 &tmat);
2840 }
2841 }
2842 # elif defined HAVE_NTGUI
2843
2844 img->xform.eM11 = matrix[0][0];
2845 img->xform.eM12 = matrix[0][1];
2846 img->xform.eM21 = matrix[1][0];
2847 img->xform.eM22 = matrix[1][1];
2848 img->xform.eDx = matrix[2][0];
2849 img->xform.eDy = matrix[2][1];
2850 # elif defined HAVE_HAIKU
2851
2852 memcpy (&img->transform, &matrix, sizeof matrix);
2853
2854
2855 if (rotate_flag)
2856 {
2857 img->transform[0][2] = extra_tx;
2858 img->transform[1][2] = extra_ty;
2859 }
2860 #endif
2861 }
2862
2863 #endif
2864
2865
2866
2867
2868 ptrdiff_t
2869 lookup_image (struct frame *f, Lisp_Object spec, int face_id)
2870 {
2871 struct image *img;
2872 EMACS_UINT hash;
2873
2874 if (FRAME_FACE_CACHE (f) == NULL)
2875 init_frame_faces (f);
2876 if (FRAME_FACE_CACHE (f)->used == 0)
2877 recompute_basic_faces (f);
2878 if (face_id < 0 || face_id >= FRAME_FACE_CACHE (f)->used)
2879 face_id = DEFAULT_FACE_ID;
2880
2881 struct face *face = FACE_FROM_ID (f, face_id);
2882 unsigned long foreground = face->foreground;
2883 unsigned long background = face->background;
2884 int font_size = face->font->pixel_size;
2885 char *font_family = SSDATA (face->lface[LFACE_FAMILY_INDEX]);
2886
2887
2888
2889 eassert (FRAME_WINDOW_P (f));
2890 eassert (valid_image_p (spec));
2891
2892
2893 hash = sxhash (filter_image_spec (spec));
2894 img = search_image_cache (f, spec, hash, foreground, background,
2895 font_size, font_family, false);
2896 if (img && img->load_failed_p)
2897 {
2898 free_image (f, img);
2899 img = NULL;
2900 }
2901
2902
2903 if (img == NULL)
2904 {
2905 block_input ();
2906 img = make_image (spec, hash);
2907 cache_image (f, img);
2908 img->face_foreground = foreground;
2909 img->face_background = background;
2910 img->face_font_size = font_size;
2911 img->face_font_family = xmalloc (strlen (font_family) + 1);
2912 strcpy (img->face_font_family, font_family);
2913 img->load_failed_p = ! img->type->load_img (f, img);
2914
2915
2916
2917
2918 if (img->load_failed_p)
2919 {
2920 Lisp_Object value;
2921
2922 value = image_spec_value (spec, QCwidth, NULL);
2923 img->width = (FIXNUMP (value)
2924 ? XFIXNAT (value) : DEFAULT_IMAGE_WIDTH);
2925 value = image_spec_value (spec, QCheight, NULL);
2926 img->height = (FIXNUMP (value)
2927 ? XFIXNAT (value) : DEFAULT_IMAGE_HEIGHT);
2928 }
2929 else
2930 {
2931
2932
2933
2934 Lisp_Object ascent, margin, relief, bg;
2935 int relief_bound;
2936
2937 ascent = image_spec_value (spec, QCascent, NULL);
2938 if (FIXNUMP (ascent))
2939 img->ascent = XFIXNUM (ascent);
2940 else if (EQ (ascent, Qcenter))
2941 img->ascent = CENTERED_IMAGE_ASCENT;
2942
2943 margin = image_spec_value (spec, QCmargin, NULL);
2944 if (FIXNUMP (margin))
2945 img->vmargin = img->hmargin = XFIXNUM (margin);
2946 else if (CONSP (margin))
2947 {
2948 img->hmargin = XFIXNUM (XCAR (margin));
2949 img->vmargin = XFIXNUM (XCDR (margin));
2950 }
2951
2952 relief = image_spec_value (spec, QCrelief, NULL);
2953 relief_bound = INT_MAX - max (img->hmargin, img->vmargin);
2954 if (RANGED_FIXNUMP (- relief_bound, relief, relief_bound))
2955 {
2956 img->relief = XFIXNUM (relief);
2957 img->hmargin += eabs (img->relief);
2958 img->vmargin += eabs (img->relief);
2959 }
2960
2961 if (! img->background_valid)
2962 {
2963 bg = image_spec_value (img->spec, QCbackground, NULL);
2964 if (!NILP (bg))
2965 {
2966 img->background
2967 = image_alloc_image_color (f, img, bg, background);
2968 img->background_valid = 1;
2969 }
2970 }
2971
2972
2973
2974 if (!EQ (builtin_lisp_symbol (img->type->type), Qpostscript))
2975 postprocess_image (f, img);
2976
2977
2978
2979
2980 #ifdef HAVE_NATIVE_TRANSFORMS
2981 image_set_transform (f, img);
2982 #endif
2983 }
2984
2985 unblock_input ();
2986 }
2987
2988
2989
2990 img->timestamp = current_timespec ();
2991
2992
2993 return img->id;
2994 }
2995
2996
2997
2998
2999 static void
3000 cache_image (struct frame *f, struct image *img)
3001 {
3002 struct image_cache *c = FRAME_IMAGE_CACHE (f);
3003 ptrdiff_t i;
3004
3005 if (!c)
3006 c = FRAME_IMAGE_CACHE (f) = make_image_cache ();
3007
3008
3009 for (i = 0; i < c->used; ++i)
3010 if (c->images[i] == NULL)
3011 break;
3012
3013
3014 if (i == c->used && c->used == c->size)
3015 c->images = xpalloc (c->images, &c->size, 1, -1, sizeof *c->images);
3016
3017
3018 c->images[i] = img;
3019 img->id = i;
3020 if (i == c->used)
3021 ++c->used;
3022
3023
3024 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
3025 img->next = c->buckets[i];
3026 if (img->next)
3027 img->next->prev = img;
3028 img->prev = NULL;
3029 c->buckets[i] = img;
3030 }
3031
3032
3033 #if defined (HAVE_WEBP) || defined (HAVE_GIF)
3034
3035
3036
3037
3038 struct anim_cache
3039 {
3040 Lisp_Object spec;
3041
3042 void *handle;
3043
3044 void *temp;
3045
3046 void (*destructor) (void *);
3047 int index, width, height, frames;
3048
3049
3050
3051
3052 int byte_size;
3053 struct timespec update_time;
3054 struct anim_cache *next;
3055 };
3056
3057 static struct anim_cache *anim_cache = NULL;
3058
3059 static struct anim_cache *
3060 anim_create_cache (Lisp_Object spec)
3061 {
3062 struct anim_cache *cache = xmalloc (sizeof (struct anim_cache));
3063 cache->handle = NULL;
3064 cache->temp = NULL;
3065
3066 cache->index = -1;
3067 cache->next = NULL;
3068 cache->spec = spec;
3069 cache->byte_size = 0;
3070 return cache;
3071 }
3072
3073
3074
3075
3076
3077 static void
3078 anim_prune_animation_cache (Lisp_Object clear)
3079 {
3080 struct anim_cache **pcache = &anim_cache;
3081 struct timespec old = timespec_sub (current_timespec (),
3082 make_timespec (60, 0));
3083
3084 while (*pcache)
3085 {
3086 struct anim_cache *cache = *pcache;
3087 if (EQ (clear, Qt)
3088 || (EQ (clear, Qnil) && timespec_cmp (old, cache->update_time) > 0)
3089 || EQ (clear, cache->spec))
3090 {
3091 if (cache->handle)
3092 cache->destructor (cache);
3093 if (cache->temp)
3094 xfree (cache->temp);
3095 *pcache = cache->next;
3096 xfree (cache);
3097 }
3098 else
3099 pcache = &cache->next;
3100 }
3101 }
3102
3103 static struct anim_cache *
3104 anim_get_animation_cache (Lisp_Object spec)
3105 {
3106 struct anim_cache *cache;
3107 struct anim_cache **pcache = &anim_cache;
3108
3109 anim_prune_animation_cache (Qnil);
3110
3111 while (1)
3112 {
3113 cache = *pcache;
3114 if (! cache)
3115 {
3116 *pcache = cache = anim_create_cache (spec);
3117 break;
3118 }
3119 if (EQ (spec, cache->spec))
3120 break;
3121 pcache = &cache->next;
3122 }
3123
3124 cache->update_time = current_timespec ();
3125 return cache;
3126 }
3127
3128 #endif
3129
3130
3131
3132
3133
3134
3135 static void
3136 mark_image (struct image *img)
3137 {
3138 mark_object (img->spec);
3139 mark_object (img->dependencies);
3140
3141 if (!NILP (img->lisp_data))
3142 mark_object (img->lisp_data);
3143 }
3144
3145
3146 void
3147 mark_image_cache (struct image_cache *c)
3148 {
3149 if (c)
3150 {
3151 ptrdiff_t i;
3152 for (i = 0; i < c->used; ++i)
3153 if (c->images[i])
3154 mark_image (c->images[i]);
3155 }
3156
3157 #if defined HAVE_WEBP || defined HAVE_GIF
3158 for (struct anim_cache *cache = anim_cache; cache; cache = cache->next)
3159 mark_object (cache->spec);
3160 #endif
3161 }
3162
3163
3164
3165
3166
3167
3168
3169 #ifdef HAVE_X_WINDOWS
3170 static bool
3171 x_check_image_size (XImage *ximg, int width, int height)
3172 {
3173
3174
3175
3176 enum
3177 {
3178 XLIB_BYTES_MAX = min (INT_MAX, UINT_MAX),
3179 X_IMAGE_BYTES_MAX = min (XLIB_BYTES_MAX, min (PTRDIFF_MAX, SIZE_MAX))
3180 };
3181
3182 int bitmap_pad, depth, bytes_per_line;
3183 if (ximg)
3184 {
3185 bitmap_pad = ximg->bitmap_pad;
3186 depth = ximg->depth;
3187 bytes_per_line = ximg->bytes_per_line;
3188 }
3189 else
3190 {
3191 bitmap_pad = 8;
3192 depth = 1;
3193 bytes_per_line = (width >> 3) + ((width & 7) != 0);
3194 }
3195 return (width <= (INT_MAX - (bitmap_pad - 1)) / depth
3196 && height <= X_IMAGE_BYTES_MAX / bytes_per_line);
3197 }
3198
3199 static bool
3200 x_create_x_image_and_pixmap (struct frame *f, int width, int height, int depth,
3201 XImage **ximg, Pixmap *pixmap)
3202 {
3203 Display *display = FRAME_X_DISPLAY (f);
3204 Drawable drawable = FRAME_X_DRAWABLE (f);
3205
3206 eassert (input_blocked_p ());
3207
3208 if (depth <= 0)
3209 depth = FRAME_DISPLAY_INFO (f)->n_planes;
3210 *ximg = XCreateImage (display, FRAME_X_VISUAL (f),
3211 depth, ZPixmap, 0, NULL, width, height,
3212 depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
3213 if (*ximg == NULL)
3214 {
3215 image_error ("Unable to allocate X image");
3216 return 0;
3217 }
3218
3219 if (! x_check_image_size (*ximg, width, height))
3220 {
3221 x_destroy_x_image (*ximg);
3222 *ximg = NULL;
3223 image_error ("Image too large (%dx%d)",
3224 make_fixnum (width), make_fixnum (height));
3225 return 0;
3226 }
3227
3228
3229 (*ximg)->data = xmalloc ((*ximg)->bytes_per_line * height);
3230
3231
3232 *pixmap = XCreatePixmap (display, drawable, width, height, depth);
3233 if (*pixmap == NO_PIXMAP)
3234 {
3235 x_destroy_x_image (*ximg);
3236 *ximg = NULL;
3237 image_error ("Unable to create X pixmap");
3238 return 0;
3239 }
3240
3241 return 1;
3242 }
3243
3244 static void
3245 x_destroy_x_image (XImage *ximg)
3246 {
3247 if (ximg)
3248 {
3249 xfree (ximg->data);
3250 ximg->data = NULL;
3251 }
3252
3253 XDestroyImage (ximg);
3254 }
3255
3256 # if !defined USE_CAIRO && defined HAVE_XRENDER
3257
3258 static Picture
3259 x_create_xrender_picture (struct frame *f, Emacs_Pixmap pixmap, int depth)
3260 {
3261 Picture p;
3262 Display *display = FRAME_X_DISPLAY (f);
3263
3264 if (FRAME_DISPLAY_INFO (f)->xrender_supported_p)
3265 {
3266 if (depth <= 0)
3267 depth = FRAME_DISPLAY_INFO (f)->n_planes;
3268 if (depth == 32 || depth == 24 || depth == 8 || depth == 4 || depth == 1)
3269 {
3270
3271
3272
3273
3274
3275
3276
3277 XRenderPictFormat *format;
3278 format = XRenderFindStandardFormat (display,
3279 depth == 32 ? PictStandardARGB32
3280 : depth == 24 ? PictStandardRGB24
3281 : depth == 8 ? PictStandardA8
3282 : depth == 4 ? PictStandardA4
3283 : PictStandardA1);
3284
3285
3286
3287
3288
3289 XRenderPictureAttributes attr;
3290 unsigned long attr_mask = CPRepeat;
3291 attr.repeat = RepeatPad;
3292
3293 p = XRenderCreatePicture (display, pixmap, format, attr_mask, &attr);
3294 }
3295 else
3296 {
3297 image_error ("Specified image bit depth is not supported by XRender");
3298 return 0;
3299 }
3300 }
3301 else
3302 {
3303
3304 return 0;
3305 }
3306
3307 return p;
3308 }
3309 # endif
3310 #endif
3311
3312
3313
3314
3315
3316
3317 static bool
3318 image_check_image_size (Emacs_Pix_Container ximg, int width, int height)
3319 {
3320 #if defined HAVE_X_WINDOWS && !defined USE_CAIRO
3321 return x_check_image_size (ximg, width, height);
3322 #else
3323
3324
3325 return 1;
3326 #endif
3327 }
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339 static bool
3340 image_create_x_image_and_pixmap_1 (struct frame *f, int width, int height, int depth,
3341 Emacs_Pix_Container *pimg,
3342 Emacs_Pixmap *pixmap, Picture *picture)
3343 {
3344 #ifdef USE_CAIRO
3345 eassert (input_blocked_p ());
3346
3347
3348 *pixmap = image_create_pix_container (width, height, depth);
3349 if (*pixmap == NO_PIXMAP)
3350 {
3351 *pimg = NULL;
3352 image_error ("Unable to create X pixmap", Qnil, Qnil);
3353 return 0;
3354 }
3355
3356 *pimg = *pixmap;
3357 return 1;
3358 #elif defined HAVE_X_WINDOWS
3359 if (!x_create_x_image_and_pixmap (f, width, height, depth, pimg, pixmap))
3360 return 0;
3361 # ifdef HAVE_XRENDER
3362 if (picture)
3363 *picture = x_create_xrender_picture (f, *pixmap, depth);
3364 # endif
3365
3366 return 1;
3367 #endif
3368
3369 #ifdef HAVE_HAIKU
3370 if (depth == 0)
3371 depth = 24;
3372
3373 if (depth != 24 && depth != 1)
3374 {
3375 *pimg = NULL;
3376 image_error ("Invalid image bit depth specified");
3377 return 0;
3378 }
3379
3380 *pixmap = BBitmap_new (width, height, depth == 1);
3381
3382 if (*pixmap == NO_PIXMAP)
3383 {
3384 *pimg = NULL;
3385 image_error ("Unable to create pixmap", Qnil, Qnil);
3386 return 0;
3387 }
3388
3389 *pimg = *pixmap;
3390 return 1;
3391 #endif
3392
3393 #ifdef HAVE_NTGUI
3394
3395 BITMAPINFOHEADER *header;
3396 HDC hdc;
3397 int scanline_width_bits;
3398 int remainder;
3399 int palette_colors = 0;
3400
3401 if (depth == 0)
3402 depth = 24;
3403
3404 if (depth != 1 && depth != 4 && depth != 8
3405 && depth != 16 && depth != 24 && depth != 32)
3406 {
3407 image_error ("Invalid image bit depth specified");
3408 return 0;
3409 }
3410
3411 scanline_width_bits = width * depth;
3412 remainder = scanline_width_bits % 32;
3413
3414 if (remainder)
3415 scanline_width_bits += 32 - remainder;
3416
3417
3418
3419 if (depth < 16)
3420 palette_colors = 1 << (depth - 1);
3421
3422 *pimg = xmalloc (sizeof (XImage) + palette_colors * sizeof (RGBQUAD));
3423
3424 header = &(*pimg)->info.bmiHeader;
3425 memset (&(*pimg)->info, 0, sizeof (BITMAPINFO));
3426 header->biSize = sizeof (*header);
3427 header->biWidth = width;
3428 header->biHeight = -height;
3429 header->biPlanes = 1;
3430 header->biBitCount = depth;
3431 header->biCompression = BI_RGB;
3432 header->biClrUsed = palette_colors;
3433
3434
3435 if (depth == 1)
3436 {
3437 (*pimg)->info.bmiColors[0].rgbBlue = 0;
3438 (*pimg)->info.bmiColors[0].rgbGreen = 0;
3439 (*pimg)->info.bmiColors[0].rgbRed = 0;
3440 (*pimg)->info.bmiColors[0].rgbReserved = 0;
3441
3442
3443
3444 # if GNUC_PREREQ (4, 4, 0)
3445 # pragma GCC push_options
3446 # pragma GCC diagnostic ignored "-Warray-bounds"
3447 # endif
3448 (*pimg)->info.bmiColors[1].rgbBlue = 255;
3449 (*pimg)->info.bmiColors[1].rgbGreen = 255;
3450 (*pimg)->info.bmiColors[1].rgbRed = 255;
3451 (*pimg)->info.bmiColors[1].rgbReserved = 0;
3452 # if GNUC_PREREQ (4, 4, 0)
3453 # pragma GCC pop_options
3454 # endif
3455 }
3456
3457 hdc = get_frame_dc (f);
3458
3459
3460
3461 *pixmap = CreateDIBSection (hdc, &(*pimg)->info,
3462 (depth < 16) ? DIB_PAL_COLORS : DIB_RGB_COLORS,
3463
3464 (void **) &(*pimg)->data, NULL, 0);
3465
3466
3467 release_frame_dc (f, hdc);
3468
3469 if (*pixmap == NULL)
3470 {
3471 DWORD err = GetLastError ();
3472 Lisp_Object errcode;
3473
3474 XSETINT (errcode, err);
3475 image_error ("Unable to create bitmap, error code %d", errcode);
3476 image_destroy_x_image (*pimg);
3477 *pimg = NULL;
3478 return 0;
3479 }
3480
3481 return 1;
3482
3483 #endif
3484
3485 #ifdef HAVE_NS
3486 *pixmap = ns_image_for_XPM (width, height, depth);
3487 if (*pixmap == 0)
3488 {
3489 *pimg = NULL;
3490 image_error ("Unable to allocate NSImage for XPM pixmap");
3491 return 0;
3492 }
3493 *pimg = *pixmap;
3494 return 1;
3495 #endif
3496 }
3497
3498
3499
3500
3501 static void
3502 image_destroy_x_image (Emacs_Pix_Container pimg)
3503 {
3504 #if defined HAVE_X_WINDOWS && !defined USE_CAIRO
3505 x_destroy_x_image (pimg);
3506 #else
3507 eassert (input_blocked_p ());
3508 if (pimg)
3509 {
3510 #ifdef USE_CAIRO
3511 #endif
3512 #ifdef HAVE_NTGUI
3513
3514 pimg->data = NULL;
3515 xfree (pimg);
3516 #endif
3517 #ifdef HAVE_NS
3518 ns_release_object (pimg);
3519 #endif
3520 }
3521 #endif
3522 }
3523
3524
3525
3526
3527
3528
3529 static void
3530 gui_put_x_image (struct frame *f, Emacs_Pix_Container pimg,
3531 Emacs_Pixmap pixmap, int width, int height)
3532 {
3533 #if defined USE_CAIRO || defined HAVE_HAIKU
3534 eassert (pimg == pixmap);
3535 #elif defined HAVE_X_WINDOWS
3536 GC gc;
3537
3538 eassert (input_blocked_p ());
3539 gc = XCreateGC (FRAME_X_DISPLAY (f), pixmap, 0, NULL);
3540 XPutImage (FRAME_X_DISPLAY (f), pixmap, gc, pimg, 0, 0, 0, 0,
3541 pimg->width, pimg->height);
3542 XFreeGC (FRAME_X_DISPLAY (f), gc);
3543 #endif
3544
3545 #ifdef HAVE_NS
3546 eassert (pimg == pixmap);
3547 ns_retain_object (pimg);
3548 #endif
3549 }
3550
3551
3552
3553
3554 static bool
3555 image_create_x_image_and_pixmap (struct frame *f, struct image *img,
3556 int width, int height, int depth,
3557 Emacs_Pix_Container *ximg, bool mask_p)
3558 {
3559 eassert ((!mask_p ? img->pixmap : img->mask) == NO_PIXMAP);
3560
3561 Picture *picture = NULL;
3562 #if !defined USE_CAIRO && defined HAVE_XRENDER
3563 picture = !mask_p ? &img->picture : &img->mask_picture;
3564 #endif
3565 return image_create_x_image_and_pixmap_1 (f, width, height, depth, ximg,
3566 !mask_p ? &img->pixmap : &img->mask,
3567 picture);
3568 }
3569
3570
3571
3572
3573
3574
3575
3576 static void
3577 image_put_x_image (struct frame *f, struct image *img, Emacs_Pix_Container ximg,
3578 bool mask_p)
3579 {
3580 #if defined HAVE_X_WINDOWS && !defined USE_CAIRO
3581 if (!mask_p)
3582 {
3583 eassert (img->ximg == NULL);
3584 img->ximg = ximg;
3585 }
3586 else
3587 {
3588 eassert (img->mask_img == NULL);
3589 img->mask_img = ximg;
3590 }
3591 #else
3592 gui_put_x_image (f, ximg, !mask_p ? img->pixmap : img->mask,
3593 img->width, img->height);
3594 image_destroy_x_image (ximg);
3595 #endif
3596 }
3597
3598 #if defined HAVE_X_WINDOWS && !defined USE_CAIRO
3599
3600
3601
3602 static void
3603 image_sync_to_pixmaps (struct frame *f, struct image *img)
3604 {
3605 if (img->ximg)
3606 {
3607 gui_put_x_image (f, img->ximg, img->pixmap, img->width, img->height);
3608 image_destroy_x_image (img->ximg);
3609 img->ximg = NULL;
3610 }
3611 if (img->mask_img)
3612 {
3613 gui_put_x_image (f, img->mask_img, img->mask, img->width, img->height);
3614 image_destroy_x_image (img->mask_img);
3615 img->mask_img = NULL;
3616 }
3617 }
3618 #endif
3619
3620 #ifdef HAVE_NTGUI
3621
3622
3623
3624
3625 static HDC
3626 image_get_x_image_or_dc (struct frame *f, struct image *img, bool mask_p,
3627 HGDIOBJ *prev)
3628 {
3629 HDC frame_dc = get_frame_dc (f);
3630 HDC ximg = CreateCompatibleDC (frame_dc);
3631
3632 release_frame_dc (f, frame_dc);
3633 *prev = SelectObject (ximg, !mask_p ? img->pixmap : img->mask);
3634
3635 return ximg;
3636 }
3637
3638 static void
3639 image_unget_x_image_or_dc (struct image *img, bool mask_p,
3640 HDC ximg, HGDIOBJ prev)
3641 {
3642 SelectObject (ximg, prev);
3643 DeleteDC (ximg);
3644 }
3645 #else
3646
3647
3648
3649 static Emacs_Pix_Container
3650 image_get_x_image (struct frame *f, struct image *img, bool mask_p)
3651 {
3652 #if defined USE_CAIRO || defined (HAVE_HAIKU)
3653 return !mask_p ? img->pixmap : img->mask;
3654 #elif defined HAVE_X_WINDOWS
3655 XImage *ximg_in_img = !mask_p ? img->ximg : img->mask_img;
3656
3657 if (ximg_in_img)
3658 return ximg_in_img;
3659 #ifdef HAVE_XRENDER
3660 else if (img->picture)
3661 return XGetImage (FRAME_X_DISPLAY (f), !mask_p ? img->pixmap : img->mask,
3662 0, 0, img->original_width, img->original_height, ~0, ZPixmap);
3663 #endif
3664 else
3665 return XGetImage (FRAME_X_DISPLAY (f), !mask_p ? img->pixmap : img->mask,
3666 0, 0, img->width, img->height, ~0, ZPixmap);
3667 #elif defined (HAVE_NS)
3668 Emacs_Pix_Container pixmap = !mask_p ? img->pixmap : img->mask;
3669
3670 ns_retain_object (pixmap);
3671 return pixmap;
3672 #endif
3673 }
3674
3675 static void
3676 image_unget_x_image (struct image *img, bool mask_p, Emacs_Pix_Container ximg)
3677 {
3678 #ifdef USE_CAIRO
3679 #elif defined HAVE_X_WINDOWS
3680 XImage *ximg_in_img = !mask_p ? img->ximg : img->mask_img;
3681
3682 if (ximg_in_img)
3683 eassert (ximg == ximg_in_img);
3684 else
3685 XDestroyImage (ximg);
3686 #elif defined (HAVE_NS)
3687 ns_release_object (ximg);
3688 #endif
3689 }
3690 #endif
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703 static Lisp_Object
3704 image_find_image_fd (Lisp_Object file, int *pfd)
3705 {
3706 Lisp_Object file_found, search_path;
3707 int fd;
3708
3709
3710
3711 search_path = Fcons (Fexpand_file_name (build_string ("images"),
3712 Vdata_directory),
3713 Vx_bitmap_file_path);
3714
3715
3716 fd = openp (search_path, file, Qnil, &file_found,
3717 pfd ? Qt : make_fixnum (R_OK), false, false);
3718 if (fd == -2)
3719 {
3720
3721
3722
3723
3724 Lisp_Object encoded_name = ENCODE_FILE (file_found);
3725 fd = emacs_open (SSDATA (encoded_name), O_RDONLY, 0);
3726 }
3727 else if (fd < 0)
3728 return Qnil;
3729 if (pfd)
3730 *pfd = fd;
3731 return file_found;
3732 }
3733
3734
3735
3736
3737
3738 Lisp_Object
3739 image_find_image_file (Lisp_Object file)
3740 {
3741 return image_find_image_fd (file, 0);
3742 }
3743
3744
3745
3746
3747
3748
3749 static char *
3750 slurp_file (int fd, ptrdiff_t *size)
3751 {
3752 FILE *fp = fdopen (fd, "rb");
3753
3754 char *buf = NULL;
3755 struct stat st;
3756
3757 if (fp)
3758 {
3759 specpdl_ref count = SPECPDL_INDEX ();
3760 record_unwind_protect_ptr (fclose_unwind, fp);
3761
3762 if (fstat (fileno (fp), &st) == 0
3763 && 0 <= st.st_size && st.st_size < min (PTRDIFF_MAX, SIZE_MAX))
3764 {
3765
3766
3767 ptrdiff_t buflen = st.st_size;
3768 buf = xmalloc (buflen + 1);
3769 if (fread (buf, 1, buflen + 1, fp) == buflen)
3770 *size = buflen;
3771 else
3772 {
3773 xfree (buf);
3774 buf = NULL;
3775 }
3776 }
3777
3778 unbind_to (count, Qnil);
3779 }
3780
3781 return buf;
3782 }
3783
3784
3785
3786
3787
3788
3789
3790 static bool xbm_file_p (Lisp_Object);
3791
3792
3793
3794
3795 enum xbm_keyword_index
3796 {
3797 XBM_TYPE,
3798 XBM_FILE,
3799 XBM_WIDTH,
3800 XBM_HEIGHT,
3801 XBM_STRIDE,
3802 XBM_DATA,
3803 XBM_FOREGROUND,
3804 XBM_BACKGROUND,
3805 XBM_ASCENT,
3806 XBM_MARGIN,
3807 XBM_RELIEF,
3808 XBM_ALGORITHM,
3809 XBM_HEURISTIC_MASK,
3810 XBM_MASK,
3811 XBM_DATA_WIDTH,
3812 XBM_DATA_HEIGHT,
3813 XBM_LAST
3814 };
3815
3816
3817
3818
3819 static const struct image_keyword xbm_format[XBM_LAST] =
3820 {
3821 {":type", IMAGE_SYMBOL_VALUE, 1},
3822 {":file", IMAGE_STRING_VALUE, 0},
3823 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
3824 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
3825 {":stride", IMAGE_POSITIVE_INTEGER_VALUE, 0},
3826 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3827 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
3828 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
3829 {":ascent", IMAGE_ASCENT_VALUE, 0},
3830 {":margin", IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR, 0},
3831 {":relief", IMAGE_INTEGER_VALUE, 0},
3832 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3833 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3834 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3835 {":data-width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
3836 {":data-height", IMAGE_POSITIVE_INTEGER_VALUE, 0}
3837 };
3838
3839
3840
3841 enum xbm_token
3842 {
3843 XBM_TK_IDENT = 256,
3844 XBM_TK_NUMBER,
3845 XBM_TK_OVERFLOW
3846 };
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876 static bool
3877 xbm_image_p (Lisp_Object object)
3878 {
3879 struct image_keyword kw[XBM_LAST];
3880
3881 memcpy (kw, xbm_format, sizeof kw);
3882 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
3883 return 0;
3884
3885 eassert (EQ (kw[XBM_TYPE].value, Qxbm));
3886
3887 if (kw[XBM_FILE].count)
3888 {
3889 if (kw[XBM_DATA].count)
3890 return 0;
3891 }
3892 else if (kw[XBM_DATA].count && xbm_file_p (kw[XBM_DATA].value))
3893 {
3894
3895 if (kw[XBM_FILE].count)
3896 return 0;
3897 }
3898 else
3899 {
3900 Lisp_Object data;
3901 int width, height, stride;
3902
3903
3904 if (!kw[XBM_DATA_WIDTH].count
3905 || !kw[XBM_DATA_HEIGHT].count
3906 || !kw[XBM_DATA].count)
3907 return 0;
3908
3909 data = kw[XBM_DATA].value;
3910 width = XFIXNAT (kw[XBM_DATA_WIDTH].value);
3911 height = XFIXNAT (kw[XBM_DATA_HEIGHT].value);
3912
3913 if (!kw[XBM_STRIDE].count)
3914 stride = width;
3915 else
3916 stride = XFIXNAT (kw[XBM_STRIDE].value);
3917
3918
3919
3920 if (VECTORP (data))
3921 {
3922 EMACS_INT i;
3923
3924
3925 if (ASIZE (data) < height)
3926 return 0;
3927
3928
3929
3930 for (i = 0; i < height; ++i)
3931 {
3932 Lisp_Object elt = AREF (data, i);
3933
3934 if (STRINGP (elt))
3935 {
3936 if (SCHARS (elt) < stride / CHAR_BIT)
3937 return 0;
3938 }
3939 else if (BOOL_VECTOR_P (elt))
3940 {
3941 if (bool_vector_size (elt) < width)
3942 return 0;
3943 }
3944 else
3945 return 0;
3946 }
3947 }
3948 else if (STRINGP (data))
3949 {
3950 if (SCHARS (data) < stride / CHAR_BIT * height)
3951 return 0;
3952 }
3953 else if (BOOL_VECTOR_P (data))
3954 {
3955 if (height > 1 && stride != (width + CHAR_BIT - 1)
3956 / CHAR_BIT * CHAR_BIT)
3957 return 0;
3958
3959 if (bool_vector_size (data) / height < stride)
3960 return 0;
3961 }
3962 else
3963 return 0;
3964 }
3965
3966 return 1;
3967 }
3968
3969
3970
3971
3972
3973
3974
3975
3976 static int
3977 xbm_scan (char **s, char *end, char *sval, int *ival)
3978 {
3979 unsigned char c UNINIT;
3980 char *sval_end = sval + BUFSIZ;
3981
3982 loop:
3983
3984
3985 while (*s < end && (c = *(*s)++, c_isspace (c)))
3986 ;
3987
3988 if (*s >= end)
3989 c = 0;
3990 else if (c_isdigit (c))
3991 {
3992 int value = 0, digit;
3993 bool overflow = false;
3994
3995 if (c == '0' && *s < end)
3996 {
3997 c = *(*s)++;
3998 if (c == 'x' || c == 'X')
3999 {
4000 while (*s < end)
4001 {
4002 c = *(*s)++;
4003 digit = char_hexdigit (c);
4004 if (digit < 0)
4005 break;
4006 overflow |= INT_MULTIPLY_WRAPV (value, 16, &value);
4007 value += digit;
4008 }
4009 }
4010 else if ('0' <= c && c <= '7')
4011 {
4012 value = c - '0';
4013 while (*s < end
4014 && (c = *(*s)++, '0' <= c && c <= '7'))
4015 {
4016 overflow |= INT_MULTIPLY_WRAPV (value, 8, &value);
4017 value += c - '0';
4018 }
4019 }
4020 }
4021 else
4022 {
4023 value = c - '0';
4024 while (*s < end
4025 && (c = *(*s)++, c_isdigit (c)))
4026 {
4027 overflow |= INT_MULTIPLY_WRAPV (value, 10, &value);
4028 overflow |= INT_ADD_WRAPV (value, c - '0', &value);
4029 }
4030 }
4031
4032 if (*s < end)
4033 *s = *s - 1;
4034 *ival = value;
4035 return overflow ? XBM_TK_OVERFLOW : XBM_TK_NUMBER;
4036 }
4037
4038
4039
4040 else if (c == '\'')
4041 {
4042 int value = 0, digit;
4043 bool overflow = false;
4044
4045 if (*s == end)
4046 return 0;
4047
4048 c = *(*s)++;
4049
4050 if (c != '\\' || *s == end)
4051 return 0;
4052
4053 c = *(*s)++;
4054
4055 if (c == 'x')
4056 {
4057 while (*s < end)
4058 {
4059 c = *(*s)++;
4060
4061 if (c == '\'')
4062 {
4063 *ival = value;
4064 return overflow ? XBM_TK_OVERFLOW : XBM_TK_NUMBER;
4065 }
4066
4067 digit = char_hexdigit (c);
4068
4069 if (digit < 0)
4070 return 0;
4071
4072 overflow |= INT_MULTIPLY_WRAPV (value, 16, &value);
4073 value += digit;
4074 }
4075 }
4076
4077 return 0;
4078 }
4079 else if (c_isalpha (c) || c == '_')
4080 {
4081 *sval++ = c;
4082 while (*s < end && sval < sval_end
4083 && (c = *(*s)++, (c_isalnum (c) || c == '_')))
4084 *sval++ = c;
4085 *sval = 0;
4086 if (*s < end)
4087 *s = *s - 1;
4088 return XBM_TK_IDENT;
4089 }
4090 else if (c == '/' && **s == '*')
4091 {
4092
4093 ++*s;
4094 while (**s && (**s != '*' || *(*s + 1) != '/'))
4095 ++*s;
4096 if (**s)
4097 {
4098 *s += 2;
4099 goto loop;
4100 }
4101 }
4102
4103 return c;
4104 }
4105
4106 #ifdef HAVE_NTGUI
4107
4108
4109 static HBITMAP
4110 w32_create_pixmap_from_bitmap_data (int width, int height, char *data)
4111 {
4112 static unsigned char swap_nibble[16]
4113 = { 0x0, 0x8, 0x4, 0xc,
4114 0x2, 0xa, 0x6, 0xe,
4115 0x1, 0x9, 0x5, 0xd,
4116 0x3, 0xb, 0x7, 0xf };
4117 int i, j, w1, w2;
4118 unsigned char *bits, *p;
4119 HBITMAP bmp;
4120
4121 w1 = (width + 7) / 8;
4122 w2 = ((width + 15) / 16) * 2;
4123 bits = alloca (height * w2);
4124 memset (bits, 0, height * w2);
4125 for (i = 0; i < height; i++)
4126 {
4127 p = bits + i*w2;
4128 for (j = 0; j < w1; j++)
4129 {
4130
4131 unsigned char c = *data++;
4132 *p++ = (unsigned char)((swap_nibble[c & 0xf] << 4)
4133 | (swap_nibble[(c>>4) & 0xf]));
4134 }
4135 }
4136 bmp = CreateBitmap (width, height, 1, 1, (char *) bits);
4137
4138 return bmp;
4139 }
4140
4141 static void
4142 convert_mono_to_color_image (struct frame *f, struct image *img,
4143 COLORREF foreground, COLORREF background)
4144 {
4145 HDC hdc, old_img_dc, new_img_dc;
4146 HGDIOBJ old_prev, new_prev;
4147 HBITMAP new_pixmap;
4148
4149 hdc = get_frame_dc (f);
4150 old_img_dc = CreateCompatibleDC (hdc);
4151 new_img_dc = CreateCompatibleDC (hdc);
4152 new_pixmap = CreateCompatibleBitmap (hdc, img->width, img->height);
4153 release_frame_dc (f, hdc);
4154 old_prev = SelectObject (old_img_dc, img->pixmap);
4155 new_prev = SelectObject (new_img_dc, new_pixmap);
4156 SetTextColor (new_img_dc, foreground);
4157 SetBkColor (new_img_dc, background);
4158
4159 BitBlt (new_img_dc, 0, 0, img->width, img->height, old_img_dc,
4160 0, 0, SRCCOPY);
4161
4162 SelectObject (old_img_dc, old_prev);
4163 SelectObject (new_img_dc, new_prev);
4164 DeleteDC (old_img_dc);
4165 DeleteDC (new_img_dc);
4166 DeleteObject (img->pixmap);
4167 if (new_pixmap == 0)
4168 fputs ("Failed to convert image to color.\n", stderr);
4169 else
4170 img->pixmap = new_pixmap;
4171 }
4172
4173 #define XBM_BIT_SHUFFLE(b) (~(b))
4174
4175 #else
4176
4177 #define XBM_BIT_SHUFFLE(b) (b)
4178
4179 #endif
4180
4181
4182 static void
4183 Create_Pixmap_From_Bitmap_Data (struct frame *f, struct image *img, char *data,
4184 RGB_PIXEL_COLOR fg, RGB_PIXEL_COLOR bg,
4185 bool non_default_colors)
4186 {
4187 #ifdef USE_CAIRO
4188 Emacs_Color fgbg[] = {{.pixel = fg}, {.pixel = bg}};
4189 FRAME_TERMINAL (f)->query_colors (f, fgbg, ARRAYELTS (fgbg));
4190 fg = lookup_rgb_color (f, fgbg[0].red, fgbg[0].green, fgbg[0].blue);
4191 bg = lookup_rgb_color (f, fgbg[1].red, fgbg[1].green, fgbg[1].blue);
4192 img->pixmap
4193 = image_pix_container_create_from_bitmap_data (f, data, img->width,
4194 img->height, fg, bg);
4195 #elif defined HAVE_X_WINDOWS
4196 img->pixmap
4197 = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
4198 FRAME_X_DRAWABLE (f),
4199 data,
4200 img->width, img->height,
4201 fg, bg,
4202 FRAME_DISPLAY_INFO (f)->n_planes);
4203 # if !defined USE_CAIRO && defined HAVE_XRENDER
4204 if (img->pixmap)
4205 img->picture = x_create_xrender_picture (f, img->pixmap, 0);
4206 # endif
4207
4208 #elif defined HAVE_NTGUI
4209 img->pixmap
4210 = w32_create_pixmap_from_bitmap_data (img->width, img->height, data);
4211
4212
4213 if (non_default_colors)
4214 convert_mono_to_color_image (f, img, fg, bg);
4215 #elif defined HAVE_NS
4216 img->pixmap = ns_image_from_XBM (data, img->width, img->height, fg, bg);
4217 #elif defined HAVE_HAIKU
4218 img->pixmap = BBitmap_new (img->width, img->height, 0);
4219
4220 if (img->pixmap)
4221 {
4222 int bytes_per_line = (img->width + 7) / 8;
4223
4224 for (int y = 0; y < img->height; y++)
4225 {
4226 for (int x = 0; x < img->width; x++)
4227 PUT_PIXEL (img->pixmap, x, y,
4228 (data[x / 8] >> (x % 8)) & 1 ? fg : bg);
4229 data += bytes_per_line;
4230 }
4231 }
4232 #endif
4233 }
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246 static bool
4247 xbm_read_bitmap_data (struct frame *f, char *contents, char *end,
4248 int *width, int *height, char **data,
4249 bool inhibit_image_error)
4250 {
4251 char *s = contents;
4252 char buffer[BUFSIZ];
4253 bool padding_p = 0;
4254 bool v10 = 0;
4255 int bytes_per_line, i, nbytes;
4256 char *p;
4257 int value;
4258 int LA1;
4259
4260 #define match() \
4261 LA1 = xbm_scan (&s, end, buffer, &value)
4262
4263 #define expect(TOKEN) \
4264 do \
4265 { \
4266 if (LA1 != (TOKEN)) \
4267 goto failure; \
4268 match (); \
4269 } \
4270 while (0)
4271
4272 #define expect_ident(IDENT) \
4273 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
4274 match (); \
4275 else \
4276 goto failure
4277
4278 *width = *height = -1;
4279 if (data)
4280 *data = NULL;
4281 LA1 = xbm_scan (&s, end, buffer, &value);
4282
4283
4284 while (LA1 == '#')
4285 {
4286 match ();
4287 expect_ident ("define");
4288 expect (XBM_TK_IDENT);
4289
4290 if (LA1 == XBM_TK_NUMBER)
4291 {
4292 char *q = strrchr (buffer, '_');
4293 q = q ? q + 1 : buffer;
4294 if (strcmp (q, "width") == 0)
4295 *width = value;
4296 else if (strcmp (q, "height") == 0)
4297 *height = value;
4298 }
4299 expect (XBM_TK_NUMBER);
4300 }
4301
4302 if (!check_image_size (f, *width, *height))
4303 {
4304 if (!inhibit_image_error)
4305 image_size_error ();
4306 goto failure;
4307 }
4308 else if (data == NULL)
4309 goto success;
4310
4311
4312 expect_ident ("static");
4313 if (LA1 == XBM_TK_IDENT)
4314 {
4315 if (strcmp (buffer, "unsigned") == 0)
4316 {
4317 match ();
4318 expect_ident ("char");
4319 }
4320 else if (strcmp (buffer, "short") == 0)
4321 {
4322 match ();
4323 v10 = 1;
4324 if (*width % 16 && *width % 16 < 9)
4325 padding_p = 1;
4326 }
4327 else if (strcmp (buffer, "char") == 0)
4328 match ();
4329 else
4330 goto failure;
4331 }
4332 else
4333 goto failure;
4334
4335 expect (XBM_TK_IDENT);
4336 expect ('[');
4337 expect (']');
4338 expect ('=');
4339 expect ('{');
4340
4341 if (! image_check_image_size (0, *width, *height))
4342 {
4343 if (!inhibit_image_error)
4344 image_error ("Image too large (%dx%d)",
4345 make_fixnum (*width), make_fixnum (*height));
4346 goto failure;
4347 }
4348 bytes_per_line = (*width + 7) / 8 + padding_p;
4349 nbytes = bytes_per_line * *height;
4350 p = *data = xmalloc (nbytes);
4351
4352 if (v10)
4353 {
4354 for (i = 0; i < nbytes; i += 2)
4355 {
4356 int val = value;
4357 expect (XBM_TK_NUMBER);
4358
4359 *p++ = XBM_BIT_SHUFFLE (val);
4360 if (!padding_p || ((i + 2) % bytes_per_line))
4361 *p++ = XBM_BIT_SHUFFLE (value >> 8);
4362
4363 if (LA1 == ',' || LA1 == '}')
4364 match ();
4365 else
4366 goto failure;
4367 }
4368 }
4369 else
4370 {
4371 for (i = 0; i < nbytes; ++i)
4372 {
4373 int val = value;
4374 expect (XBM_TK_NUMBER);
4375
4376 *p++ = XBM_BIT_SHUFFLE (val);
4377
4378 if (LA1 == ',' || LA1 == '}')
4379 match ();
4380 else
4381 goto failure;
4382 }
4383 }
4384
4385 success:
4386 return 1;
4387
4388 failure:
4389
4390 if (data && *data)
4391 {
4392 xfree (*data);
4393 *data = NULL;
4394 }
4395 return 0;
4396
4397 #undef match
4398 #undef expect
4399 #undef expect_ident
4400 }
4401
4402
4403
4404
4405
4406
4407 static bool
4408 xbm_load_image (struct frame *f, struct image *img, char *contents, char *end)
4409 {
4410 bool rc;
4411 char *data;
4412 bool success_p = 0;
4413
4414 rc = xbm_read_bitmap_data (f, contents, end, &img->width, &img->height,
4415 &data, 0);
4416
4417 if (rc)
4418 {
4419 unsigned long foreground = img->face_foreground;
4420 unsigned long background = img->face_background;
4421 bool non_default_colors = 0;
4422 Lisp_Object value;
4423
4424 eassert (img->width > 0 && img->height > 0);
4425
4426
4427 value = image_spec_value (img->spec, QCforeground, NULL);
4428 if (!NILP (value))
4429 {
4430 foreground = image_alloc_image_color (f, img, value, foreground);
4431 non_default_colors = 1;
4432 }
4433 value = image_spec_value (img->spec, QCbackground, NULL);
4434 if (!NILP (value))
4435 {
4436 background = image_alloc_image_color (f, img, value, background);
4437 img->background = background;
4438 img->background_valid = 1;
4439 non_default_colors = 1;
4440 }
4441
4442 if (image_check_image_size (0, img->width, img->height))
4443 Create_Pixmap_From_Bitmap_Data (f, img, data,
4444 foreground, background,
4445 non_default_colors);
4446 else
4447 img->pixmap = NO_PIXMAP;
4448 xfree (data);
4449
4450 if (img->pixmap == NO_PIXMAP)
4451 {
4452 image_clear_image (f, img);
4453 image_error ("Unable to create X pixmap for `%s'", img->spec);
4454 }
4455 else
4456 success_p = 1;
4457 }
4458 else
4459 image_error ("Error loading XBM image `%s'", img->spec);
4460
4461 return success_p;
4462 }
4463
4464
4465
4466
4467 static bool
4468 xbm_file_p (Lisp_Object data)
4469 {
4470 int w, h;
4471 return (STRINGP (data)
4472 && xbm_read_bitmap_data (NULL, SSDATA (data),
4473 SSDATA (data) + SBYTES (data),
4474 &w, &h, NULL, 1));
4475 }
4476
4477
4478
4479
4480
4481 static bool
4482 xbm_load (struct frame *f, struct image *img)
4483 {
4484 bool success_p = 0;
4485 Lisp_Object file_name;
4486
4487 eassert (xbm_image_p (img->spec));
4488
4489
4490 file_name = image_spec_value (img->spec, QCfile, NULL);
4491 if (STRINGP (file_name))
4492 {
4493 int fd;
4494 Lisp_Object file = image_find_image_fd (file_name, &fd);
4495 if (!STRINGP (file))
4496 {
4497 image_error ("Cannot find image file `%s'", file_name);
4498 return 0;
4499 }
4500
4501 ptrdiff_t size;
4502 char *contents = slurp_file (fd, &size);
4503 if (contents == NULL)
4504 {
4505 image_error ("Error loading XBM image `%s'", file);
4506 return 0;
4507 }
4508
4509 success_p = xbm_load_image (f, img, contents, contents + size);
4510 xfree (contents);
4511 }
4512 else
4513 {
4514 struct image_keyword fmt[XBM_LAST];
4515 Lisp_Object data;
4516 unsigned long foreground = img->face_foreground;
4517 unsigned long background = img->face_background;
4518 bool non_default_colors = 0;
4519 char *bits;
4520 bool parsed_p;
4521 bool in_memory_file_p = 0;
4522
4523
4524 data = image_spec_value (img->spec, QCdata, NULL);
4525 in_memory_file_p = xbm_file_p (data);
4526
4527
4528 memcpy (fmt, xbm_format, sizeof fmt);
4529 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
4530 eassert (parsed_p);
4531
4532
4533 if (!in_memory_file_p)
4534 {
4535 img->width = XFIXNAT (fmt[XBM_DATA_WIDTH].value);
4536 img->height = XFIXNAT (fmt[XBM_DATA_HEIGHT].value);
4537 eassert (img->width > 0 && img->height > 0);
4538 if (!check_image_size (f, img->width, img->height))
4539 {
4540 image_size_error ();
4541 return 0;
4542 }
4543 }
4544
4545
4546 if (fmt[XBM_FOREGROUND].count
4547 && STRINGP (fmt[XBM_FOREGROUND].value))
4548 {
4549 foreground = image_alloc_image_color (f,
4550 img,
4551 fmt[XBM_FOREGROUND].value,
4552 foreground);
4553 non_default_colors = 1;
4554 }
4555
4556 if (fmt[XBM_BACKGROUND].count
4557 && STRINGP (fmt[XBM_BACKGROUND].value))
4558 {
4559 background = image_alloc_image_color (f,
4560 img,
4561 fmt[XBM_BACKGROUND].value,
4562 background);
4563 non_default_colors = 1;
4564 }
4565
4566 if (in_memory_file_p)
4567 success_p = xbm_load_image (f, img, SSDATA (data),
4568 SSDATA (data) + SBYTES (data));
4569 else
4570 {
4571 USE_SAFE_ALLOCA;
4572
4573 if (VECTORP (data))
4574 {
4575 int i;
4576 char *p;
4577 int nbytes = (img->width + CHAR_BIT - 1) / CHAR_BIT;
4578
4579 SAFE_NALLOCA (bits, nbytes, img->height);
4580 p = bits;
4581 for (i = 0; i < img->height; ++i, p += nbytes)
4582 {
4583 Lisp_Object line = AREF (data, i);
4584 if (STRINGP (line))
4585 memcpy (p, SDATA (line), nbytes);
4586 else
4587 memcpy (p, bool_vector_data (line), nbytes);
4588 }
4589 }
4590 else if (STRINGP (data))
4591 bits = SSDATA (data);
4592 else
4593 bits = (char *) bool_vector_data (data);
4594
4595 #ifdef HAVE_NTGUI
4596 {
4597 char *invertedBits;
4598 int nbytes, i;
4599
4600 invertedBits = bits;
4601 nbytes = (img->width + CHAR_BIT - 1) / CHAR_BIT * img->height;
4602 SAFE_NALLOCA (bits, 1, nbytes);
4603 for (i = 0; i < nbytes; i++)
4604 bits[i] = XBM_BIT_SHUFFLE (invertedBits[i]);
4605 }
4606 #endif
4607
4608
4609 if (image_check_image_size (0, img->width, img->height))
4610 Create_Pixmap_From_Bitmap_Data (f, img, bits,
4611 foreground, background,
4612 non_default_colors);
4613 else
4614 img->pixmap = NO_PIXMAP;
4615
4616 if (img->pixmap)
4617 success_p = 1;
4618 else
4619 {
4620 image_error ("Unable to create pixmap for XBM image `%s'",
4621 img->spec);
4622 image_clear_image (f, img);
4623 }
4624
4625 SAFE_FREE ();
4626 }
4627 }
4628
4629 return success_p;
4630 }
4631
4632
4633
4634
4635
4636
4637
4638 #if defined (HAVE_XPM) || defined (HAVE_NS) || defined (HAVE_PGTK)
4639
4640 static bool xpm_image_p (Lisp_Object object);
4641 static bool xpm_load (struct frame *f, struct image *img);
4642
4643 #endif
4644
4645 #ifdef HAVE_XPM
4646 #ifdef HAVE_NTGUI
4647
4648 #define FOR_MSW
4649
4650
4651 #define XColor xpm_XColor
4652 #define XImage xpm_XImage
4653 #define Display xpm_Display
4654 #ifdef CYGWIN
4655 #include "noX/xpm.h"
4656 #else
4657 #include "X11/xpm.h"
4658 #endif
4659 #undef FOR_MSW
4660 #undef XColor
4661 #undef XImage
4662 #undef Display
4663 #else
4664 #include "X11/xpm.h"
4665 #endif
4666 #endif
4667
4668 #if defined HAVE_XPM || defined USE_CAIRO || defined HAVE_NS || defined HAVE_HAIKU
4669
4670
4671
4672 enum xpm_keyword_index
4673 {
4674 XPM_TYPE,
4675 XPM_FILE,
4676 XPM_DATA,
4677 XPM_ASCENT,
4678 XPM_MARGIN,
4679 XPM_RELIEF,
4680 XPM_ALGORITHM,
4681 XPM_HEURISTIC_MASK,
4682 XPM_MASK,
4683 XPM_COLOR_SYMBOLS,
4684 XPM_BACKGROUND,
4685 XPM_LAST
4686 };
4687
4688 #if defined HAVE_XPM || defined HAVE_NS || defined HAVE_HAIKU || defined HAVE_PGTK
4689
4690
4691
4692 static const struct image_keyword xpm_format[XPM_LAST] =
4693 {
4694 {":type", IMAGE_SYMBOL_VALUE, 1},
4695 {":file", IMAGE_STRING_VALUE, 0},
4696 {":data", IMAGE_STRING_VALUE, 0},
4697 {":ascent", IMAGE_ASCENT_VALUE, 0},
4698 {":margin", IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR, 0},
4699 {":relief", IMAGE_INTEGER_VALUE, 0},
4700 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4701 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4702 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4703 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4704 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
4705 };
4706 #endif
4707
4708 #if defined HAVE_X_WINDOWS && !defined USE_CAIRO
4709
4710
4711
4712
4713
4714
4715 #if defined XpmAllocColor && defined XpmFreeColors && defined XpmColorClosure
4716 #define ALLOC_XPM_COLORS
4717 #endif
4718 #endif
4719
4720 #ifdef ALLOC_XPM_COLORS
4721
4722 static struct xpm_cached_color *xpm_cache_color (struct frame *, char *,
4723 XColor *, int);
4724
4725
4726
4727
4728
4729
4730
4731
4732
4733 struct xpm_cached_color
4734 {
4735
4736 struct xpm_cached_color *next;
4737
4738
4739 XColor color;
4740
4741
4742 char name[FLEXIBLE_ARRAY_MEMBER];
4743 };
4744
4745
4746
4747
4748 #define XPM_COLOR_CACHE_BUCKETS 1009
4749 static struct xpm_cached_color **xpm_color_cache;
4750
4751
4752
4753 static void
4754 xpm_init_color_cache (struct frame *f, XpmAttributes *attrs)
4755 {
4756 size_t nbytes = XPM_COLOR_CACHE_BUCKETS * sizeof *xpm_color_cache;
4757 xpm_color_cache = xzalloc (nbytes);
4758 init_color_table ();
4759
4760 if (attrs->valuemask & XpmColorSymbols)
4761 {
4762 int i;
4763 XColor color;
4764
4765 for (i = 0; i < attrs->numsymbols; ++i)
4766 if (x_parse_color (f, attrs->colorsymbols[i].value, &color))
4767 {
4768 color.pixel = lookup_rgb_color (f, color.red, color.green,
4769 color.blue);
4770 xpm_cache_color (f, attrs->colorsymbols[i].name, &color, -1);
4771 }
4772 }
4773 }
4774
4775
4776
4777 static void
4778 xpm_free_color_cache (void)
4779 {
4780 struct xpm_cached_color *p, *next;
4781 int i;
4782
4783 for (i = 0; i < XPM_COLOR_CACHE_BUCKETS; ++i)
4784 for (p = xpm_color_cache[i]; p; p = next)
4785 {
4786 next = p->next;
4787 xfree (p);
4788 }
4789
4790 xfree (xpm_color_cache);
4791 xpm_color_cache = NULL;
4792 free_color_table ();
4793 }
4794
4795
4796
4797
4798 static int
4799 xpm_color_bucket (char *color_name)
4800 {
4801 EMACS_UINT hash = hash_string (color_name, strlen (color_name));
4802 return hash % XPM_COLOR_CACHE_BUCKETS;
4803 }
4804
4805
4806
4807
4808
4809
4810 static struct xpm_cached_color *
4811 xpm_cache_color (struct frame *f, char *color_name, XColor *color, int bucket)
4812 {
4813 size_t nbytes;
4814 struct xpm_cached_color *p;
4815
4816 if (bucket < 0)
4817 bucket = xpm_color_bucket (color_name);
4818
4819 nbytes = FLEXSIZEOF (struct xpm_cached_color, name, strlen (color_name) + 1);
4820 p = xmalloc (nbytes);
4821 strcpy (p->name, color_name);
4822 p->color = *color;
4823 p->next = xpm_color_cache[bucket];
4824 xpm_color_cache[bucket] = p;
4825 return p;
4826 }
4827
4828
4829
4830
4831
4832
4833 static bool
4834 xpm_lookup_color (struct frame *f, char *color_name, XColor *color)
4835 {
4836 struct xpm_cached_color *p;
4837 int h = xpm_color_bucket (color_name);
4838
4839 for (p = xpm_color_cache[h]; p; p = p->next)
4840 if (strcmp (p->name, color_name) == 0)
4841 break;
4842
4843 if (p != NULL)
4844 *color = p->color;
4845 else if (x_parse_color (f, color_name, color))
4846 {
4847 color->pixel = lookup_rgb_color (f, color->red, color->green,
4848 color->blue);
4849 p = xpm_cache_color (f, color_name, color, h);
4850 }
4851
4852
4853 else if (strcmp ("opaque", color_name) == 0)
4854 {
4855 memset (color, 0, sizeof (XColor));
4856 color->pixel = FRAME_FOREGROUND_PIXEL (f);
4857 p = xpm_cache_color (f, color_name, color, h);
4858 }
4859
4860 return p != NULL;
4861 }
4862
4863
4864
4865
4866
4867
4868
4869 static int
4870 xpm_alloc_color (Display *dpy, Colormap cmap, char *color_name, XColor *color,
4871 void *closure)
4872 {
4873 return xpm_lookup_color (closure, color_name, color);
4874 }
4875
4876
4877
4878
4879
4880
4881 static int
4882 xpm_free_colors (Display *dpy, Colormap cmap, Pixel *pixels, int npixels, void *closure)
4883 {
4884 return 1;
4885 }
4886
4887 #endif
4888
4889
4890 #ifdef WINDOWSNT
4891
4892
4893
4894 DEF_DLL_FN (void, XpmFreeAttributes, (XpmAttributes *));
4895 DEF_DLL_FN (int, XpmCreateImageFromBuffer,
4896 (Display *, char *, xpm_XImage **,
4897 xpm_XImage **, XpmAttributes *));
4898 DEF_DLL_FN (int, XpmReadFileToImage,
4899 (Display *, char *, xpm_XImage **,
4900 xpm_XImage **, XpmAttributes *));
4901 DEF_DLL_FN (void, XImageFree, (xpm_XImage *));
4902
4903 static bool
4904 init_xpm_functions (void)
4905 {
4906 HMODULE library;
4907
4908 if (!(library = w32_delayed_load (Qxpm)))
4909 return 0;
4910
4911 LOAD_DLL_FN (library, XpmFreeAttributes);
4912 LOAD_DLL_FN (library, XpmCreateImageFromBuffer);
4913 LOAD_DLL_FN (library, XpmReadFileToImage);
4914 LOAD_DLL_FN (library, XImageFree);
4915 return 1;
4916 }
4917
4918 # undef XImageFree
4919 # undef XpmCreateImageFromBuffer
4920 # undef XpmFreeAttributes
4921 # undef XpmReadFileToImage
4922
4923 # define XImageFree fn_XImageFree
4924 # define XpmCreateImageFromBuffer fn_XpmCreateImageFromBuffer
4925 # define XpmFreeAttributes fn_XpmFreeAttributes
4926 # define XpmReadFileToImage fn_XpmReadFileToImage
4927
4928 #endif
4929
4930 #if defined HAVE_XPM || defined HAVE_NS || defined HAVE_HAIKU || defined HAVE_PGTK
4931
4932
4933
4934
4935 static bool
4936 xpm_valid_color_symbols_p (Lisp_Object color_symbols)
4937 {
4938 while (CONSP (color_symbols))
4939 {
4940 Lisp_Object sym = XCAR (color_symbols);
4941 if (!CONSP (sym)
4942 || !STRINGP (XCAR (sym))
4943 || !STRINGP (XCDR (sym)))
4944 break;
4945 color_symbols = XCDR (color_symbols);
4946 }
4947
4948 return NILP (color_symbols);
4949 }
4950
4951
4952
4953 static bool
4954 xpm_image_p (Lisp_Object object)
4955 {
4956 struct image_keyword fmt[XPM_LAST];
4957 memcpy (fmt, xpm_format, sizeof fmt);
4958 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
4959
4960 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
4961
4962
4963 && (! fmt[XPM_COLOR_SYMBOLS].count
4964 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value)));
4965 }
4966 #endif
4967
4968 #endif
4969
4970 #if defined HAVE_XPM && defined HAVE_X_WINDOWS && !defined USE_GTK
4971 ptrdiff_t
4972 x_create_bitmap_from_xpm_data (struct frame *f, const char **bits)
4973 {
4974 Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
4975 ptrdiff_t id;
4976 int rc;
4977 XpmAttributes attrs;
4978 Pixmap bitmap, mask;
4979
4980 memset (&attrs, 0, sizeof attrs);
4981
4982 attrs.visual = FRAME_X_VISUAL (f);
4983 attrs.colormap = FRAME_X_COLORMAP (f);
4984 attrs.valuemask |= XpmVisual;
4985 attrs.valuemask |= XpmColormap;
4986
4987 #ifdef ALLOC_XPM_COLORS
4988 attrs.color_closure = f;
4989 attrs.alloc_color = xpm_alloc_color;
4990 attrs.free_colors = xpm_free_colors;
4991 attrs.valuemask |= XpmAllocColor | XpmFreeColors | XpmColorClosure;
4992 xpm_init_color_cache (f, &attrs);
4993 #endif
4994
4995 rc = XpmCreatePixmapFromData (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f),
4996 (char **) bits, &bitmap, &mask, &attrs);
4997 if (rc != XpmSuccess)
4998 {
4999 XpmFreeAttributes (&attrs);
5000 return -1;
5001 }
5002
5003 id = image_allocate_bitmap_record (f);
5004 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
5005 dpyinfo->bitmaps[id - 1].have_mask = true;
5006 dpyinfo->bitmaps[id - 1].mask = mask;
5007 dpyinfo->bitmaps[id - 1].file = NULL;
5008 dpyinfo->bitmaps[id - 1].height = attrs.height;
5009 dpyinfo->bitmaps[id - 1].width = attrs.width;
5010 dpyinfo->bitmaps[id - 1].depth = attrs.depth;
5011 dpyinfo->bitmaps[id - 1].refcount = 1;
5012 #ifdef USE_CAIRO
5013 dpyinfo->bitmaps[id - 1].stipple = NULL;
5014 #endif
5015
5016 #ifdef ALLOC_XPM_COLORS
5017 xpm_free_color_cache ();
5018 #endif
5019 XpmFreeAttributes (&attrs);
5020 return id;
5021 }
5022 #endif
5023
5024
5025
5026
5027 #if defined HAVE_XPM && !defined USE_CAIRO
5028
5029 static bool
5030 xpm_load (struct frame *f, struct image *img)
5031 {
5032 int rc;
5033 XpmAttributes attrs;
5034 Lisp_Object specified_file, color_symbols;
5035 USE_SAFE_ALLOCA;
5036
5037 #ifdef HAVE_NTGUI
5038 HDC hdc;
5039 xpm_XImage * xpm_image = NULL, * xpm_mask = NULL;
5040 #endif
5041
5042
5043
5044 memset (&attrs, 0, sizeof attrs);
5045
5046 #ifndef HAVE_NTGUI
5047 attrs.visual = FRAME_X_VISUAL (f);
5048 attrs.colormap = FRAME_X_COLORMAP (f);
5049 attrs.depth = FRAME_DISPLAY_INFO (f)->n_planes;
5050 attrs.valuemask |= XpmVisual;
5051 attrs.valuemask |= XpmColormap;
5052 attrs.valuemask |= XpmDepth;
5053 #endif
5054
5055 #ifdef ALLOC_XPM_COLORS
5056
5057
5058 attrs.color_closure = f;
5059 attrs.alloc_color = xpm_alloc_color;
5060 attrs.free_colors = xpm_free_colors;
5061 attrs.valuemask |= XpmAllocColor | XpmFreeColors | XpmColorClosure;
5062 #else
5063
5064 attrs.valuemask |= XpmReturnAllocPixels;
5065 #ifdef XpmAllocCloseColors
5066 attrs.alloc_close_colors = 1;
5067 attrs.valuemask |= XpmAllocCloseColors;
5068 #else
5069 attrs.closeness = 600;
5070 attrs.valuemask |= XpmCloseness;
5071 #endif
5072 #endif
5073
5074
5075
5076 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
5077 if (CONSP (color_symbols))
5078 {
5079 Lisp_Object tail;
5080 XpmColorSymbol *xpm_syms;
5081 ptrdiff_t i, size;
5082
5083 attrs.valuemask |= XpmColorSymbols;
5084
5085
5086 attrs.numsymbols = 0;
5087 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
5088 ++attrs.numsymbols;
5089
5090
5091 SAFE_NALLOCA (xpm_syms, 1, attrs.numsymbols);
5092 size = attrs.numsymbols * sizeof *xpm_syms;
5093 memset (xpm_syms, 0, size);
5094 attrs.colorsymbols = xpm_syms;
5095
5096
5097 for (tail = color_symbols, i = 0;
5098 CONSP (tail);
5099 ++i, tail = XCDR (tail))
5100 {
5101 Lisp_Object name;
5102 Lisp_Object color;
5103 char *empty_string = (char *) "";
5104
5105 if (!CONSP (XCAR (tail)))
5106 {
5107 xpm_syms[i].name = empty_string;
5108 xpm_syms[i].value = empty_string;
5109 continue;
5110 }
5111 name = XCAR (XCAR (tail));
5112 color = XCDR (XCAR (tail));
5113 if (STRINGP (name))
5114 SAFE_ALLOCA_STRING (xpm_syms[i].name, name);
5115 else
5116 xpm_syms[i].name = empty_string;
5117 if (STRINGP (color))
5118 SAFE_ALLOCA_STRING (xpm_syms[i].value, color);
5119 else
5120 xpm_syms[i].value = empty_string;
5121 }
5122 }
5123
5124
5125
5126 #ifdef ALLOC_XPM_COLORS
5127 xpm_init_color_cache (f, &attrs);
5128 #endif
5129
5130 specified_file = image_spec_value (img->spec, QCfile, NULL);
5131
5132 #ifdef HAVE_NTGUI
5133 {
5134 HDC frame_dc = get_frame_dc (f);
5135 hdc = CreateCompatibleDC (frame_dc);
5136 release_frame_dc (f, frame_dc);
5137 }
5138 #endif
5139
5140 if (STRINGP (specified_file))
5141 {
5142 Lisp_Object file = image_find_image_file (specified_file);
5143 if (!STRINGP (file))
5144 {
5145 image_error ("Cannot find image file `%s'", specified_file);
5146 #ifdef ALLOC_XPM_COLORS
5147 xpm_free_color_cache ();
5148 #endif
5149 SAFE_FREE ();
5150 return 0;
5151 }
5152
5153 file = ENCODE_FILE (file);
5154 #ifdef HAVE_NTGUI
5155 #ifdef WINDOWSNT
5156
5157
5158
5159 file = ansi_encode_filename (file);
5160 #endif
5161
5162
5163 rc = XpmReadFileToImage (&hdc, SSDATA (file),
5164 &xpm_image, &xpm_mask,
5165 &attrs);
5166 #else
5167 rc = XpmReadFileToImage (FRAME_X_DISPLAY (f), SSDATA (file),
5168 &img->ximg, &img->mask_img,
5169 &attrs);
5170 #endif
5171 }
5172 else
5173 {
5174 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
5175 if (!STRINGP (buffer))
5176 {
5177 image_error ("Invalid image data `%s'", buffer);
5178 #ifdef ALLOC_XPM_COLORS
5179 xpm_free_color_cache ();
5180 #endif
5181 SAFE_FREE ();
5182 return 0;
5183 }
5184 #ifdef HAVE_NTGUI
5185
5186
5187 rc = XpmCreateImageFromBuffer (&hdc, SSDATA (buffer),
5188 &xpm_image, &xpm_mask,
5189 &attrs);
5190 #else
5191 rc = XpmCreateImageFromBuffer (FRAME_X_DISPLAY (f), SSDATA (buffer),
5192 &img->ximg, &img->mask_img,
5193 &attrs);
5194 #endif
5195 }
5196
5197 #ifdef HAVE_X_WINDOWS
5198 if (rc == XpmSuccess)
5199 {
5200 img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f),
5201 img->ximg->width, img->ximg->height,
5202 img->ximg->depth);
5203 if (img->pixmap == NO_PIXMAP)
5204 {
5205 image_clear_image (f, img);
5206 rc = XpmNoMemory;
5207 }
5208 else
5209 {
5210 # if !defined USE_CAIRO && defined HAVE_XRENDER
5211 img->picture = x_create_xrender_picture (f, img->pixmap,
5212 img->ximg->depth);
5213 # endif
5214 if (img->mask_img)
5215 {
5216 img->mask = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f),
5217 img->mask_img->width,
5218 img->mask_img->height,
5219 img->mask_img->depth);
5220 if (img->mask == NO_PIXMAP)
5221 {
5222 image_clear_image (f, img);
5223 rc = XpmNoMemory;
5224 }
5225 # if !defined USE_CAIRO && defined HAVE_XRENDER
5226 else
5227 img->mask_picture = x_create_xrender_picture
5228 (f, img->mask, img->mask_img->depth);
5229 # endif
5230 }
5231 }
5232 }
5233 #endif
5234
5235 if (rc == XpmSuccess)
5236 {
5237 #if defined (COLOR_TABLE_SUPPORT) && defined (ALLOC_XPM_COLORS)
5238 img->colors = colors_in_color_table (&img->ncolors);
5239 #else
5240 int i;
5241
5242 #ifdef HAVE_NTGUI
5243
5244
5245 if (xpm_image && xpm_image->bitmap)
5246 {
5247 img->pixmap = xpm_image->bitmap;
5248
5249
5250 XImageFree (xpm_image);
5251 }
5252 if (xpm_mask && xpm_mask->bitmap)
5253 {
5254
5255
5256
5257 HGDIOBJ old_obj;
5258 old_obj = SelectObject (hdc, xpm_mask->bitmap);
5259
5260 PatBlt (hdc, 0, 0, xpm_mask->width, xpm_mask->height, DSTINVERT);
5261 SelectObject (hdc, old_obj);
5262
5263 img->mask = xpm_mask->bitmap;
5264 XImageFree (xpm_mask);
5265 DeleteDC (hdc);
5266 }
5267
5268 DeleteDC (hdc);
5269 #endif
5270
5271
5272 img->colors = xnmalloc (attrs.nalloc_pixels, sizeof *img->colors);
5273 img->ncolors = attrs.nalloc_pixels;
5274 for (i = 0; i < attrs.nalloc_pixels; ++i)
5275 {
5276 img->colors[i] = attrs.alloc_pixels[i];
5277 #ifdef DEBUG_X_COLORS
5278 register_color (img->colors[i]);
5279 #endif
5280 }
5281 #endif
5282
5283 img->width = attrs.width;
5284 img->height = attrs.height;
5285 eassert (img->width > 0 && img->height > 0);
5286
5287
5288 XpmFreeAttributes (&attrs);
5289
5290 #ifdef HAVE_X_WINDOWS
5291
5292 IMAGE_BACKGROUND (img, f, img->ximg);
5293 if (img->mask_img)
5294
5295
5296 image_background_transparent (img, f, img->mask_img);
5297 #endif
5298 }
5299 else
5300 {
5301 #ifdef HAVE_NTGUI
5302 DeleteDC (hdc);
5303 #endif
5304
5305 switch (rc)
5306 {
5307 case XpmOpenFailed:
5308 image_error ("Error opening XPM file (%s)", img->spec);
5309 break;
5310
5311 case XpmFileInvalid:
5312 image_error ("Invalid XPM file (%s)", img->spec);
5313 break;
5314
5315 case XpmNoMemory:
5316 image_error ("Out of memory (%s)", img->spec);
5317 break;
5318
5319 case XpmColorFailed:
5320 image_error ("Color allocation error (%s)", img->spec);
5321 break;
5322
5323 default:
5324 image_error ("Unknown error (%s)", img->spec);
5325 break;
5326 }
5327 }
5328
5329 #ifdef ALLOC_XPM_COLORS
5330 xpm_free_color_cache ();
5331 #endif
5332 SAFE_FREE ();
5333 return rc == XpmSuccess;
5334 }
5335
5336 #endif
5337
5338 #if (defined USE_CAIRO && defined HAVE_XPM) \
5339 || (defined HAVE_NS && !defined HAVE_XPM) \
5340 || (defined HAVE_HAIKU && !defined HAVE_XPM) \
5341 || (defined HAVE_PGTK && !defined HAVE_XPM)
5342
5343
5344
5345
5346 static void xpm_put_color_table_v (Lisp_Object, const char *,
5347 int, Lisp_Object);
5348 static Lisp_Object xpm_get_color_table_v (Lisp_Object, const char *, int);
5349 static void xpm_put_color_table_h (Lisp_Object, const char *,
5350 int, Lisp_Object);
5351 static Lisp_Object xpm_get_color_table_h (Lisp_Object, const char *, int);
5352
5353
5354
5355 enum xpm_token
5356 {
5357 XPM_TK_IDENT = 256,
5358 XPM_TK_STRING,
5359 XPM_TK_EOF
5360 };
5361
5362
5363
5364
5365
5366
5367
5368
5369 static int
5370 xpm_scan (const char **s, const char *end, const char **beg, ptrdiff_t *len)
5371 {
5372 unsigned char c;
5373
5374 while (*s < end)
5375 {
5376
5377 do
5378 c = *(*s)++;
5379 while (c_isspace (c) && *s < end);
5380
5381
5382
5383 if (c_isalpha (c) || c == '_' || c == '-' || c == '+')
5384 {
5385 *beg = *s - 1;
5386 while (*s < end
5387 && (c = **s, c_isalnum (c)
5388 || c == '_' || c == '-' || c == '+'))
5389 ++*s;
5390 *len = *s - *beg;
5391 return XPM_TK_IDENT;
5392 }
5393 else if (c == '"')
5394 {
5395 *beg = *s;
5396 while (*s < end && **s != '"')
5397 ++*s;
5398 *len = *s - *beg;
5399 if (*s < end)
5400 ++*s;
5401 return XPM_TK_STRING;
5402 }
5403 else if (c == '/')
5404 {
5405 if (*s < end && **s == '*')
5406 {
5407
5408 ++*s;
5409 do
5410 {
5411 while (*s < end && *(*s)++ != '*')
5412 ;
5413 }
5414 while (*s < end && **s != '/');
5415 if (*s < end)
5416 ++*s;
5417 }
5418 else
5419 return c;
5420 }
5421 else
5422 return c;
5423 }
5424
5425 return XPM_TK_EOF;
5426 }
5427
5428
5429
5430
5431
5432
5433
5434
5435 static Lisp_Object
5436 xpm_make_color_table_v (void (**put_func) (Lisp_Object, const char *, int,
5437 Lisp_Object),
5438 Lisp_Object (**get_func) (Lisp_Object, const char *,
5439 int))
5440 {
5441 *put_func = xpm_put_color_table_v;
5442 *get_func = xpm_get_color_table_v;
5443 return make_nil_vector (256);
5444 }
5445
5446 static void
5447 xpm_put_color_table_v (Lisp_Object color_table,
5448 const char *chars_start,
5449 int chars_len,
5450 Lisp_Object color)
5451 {
5452 unsigned char uc = *chars_start;
5453 ASET (color_table, uc, color);
5454 }
5455
5456 static Lisp_Object
5457 xpm_get_color_table_v (Lisp_Object color_table,
5458 const char *chars_start,
5459 int chars_len)
5460 {
5461 unsigned char uc = *chars_start;
5462 return AREF (color_table, uc);
5463 }
5464
5465 static Lisp_Object
5466 xpm_make_color_table_h (void (**put_func) (Lisp_Object, const char *, int,
5467 Lisp_Object),
5468 Lisp_Object (**get_func) (Lisp_Object, const char *,
5469 int))
5470 {
5471 *put_func = xpm_put_color_table_h;
5472 *get_func = xpm_get_color_table_h;
5473 return make_hash_table (hashtest_equal, DEFAULT_HASH_SIZE,
5474 DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD,
5475 Qnil, false);
5476 }
5477
5478 static void
5479 xpm_put_color_table_h (Lisp_Object color_table,
5480 const char *chars_start,
5481 int chars_len,
5482 Lisp_Object color)
5483 {
5484 struct Lisp_Hash_Table *table = XHASH_TABLE (color_table);
5485 Lisp_Object chars = make_unibyte_string (chars_start, chars_len), hash_code;
5486
5487 hash_lookup (table, chars, &hash_code);
5488 hash_put (table, chars, color, hash_code);
5489 }
5490
5491 static Lisp_Object
5492 xpm_get_color_table_h (Lisp_Object color_table,
5493 const char *chars_start,
5494 int chars_len)
5495 {
5496 struct Lisp_Hash_Table *table = XHASH_TABLE (color_table);
5497 ptrdiff_t i =
5498 hash_lookup (table, make_unibyte_string (chars_start, chars_len), NULL);
5499
5500 return i >= 0 ? HASH_VALUE (table, i) : Qnil;
5501 }
5502
5503 enum xpm_color_key {
5504 XPM_COLOR_KEY_S,
5505 XPM_COLOR_KEY_M,
5506 XPM_COLOR_KEY_G4,
5507 XPM_COLOR_KEY_G,
5508 XPM_COLOR_KEY_C
5509 };
5510
5511 static const char xpm_color_key_strings[][4] = {"s", "m", "g4", "g", "c"};
5512
5513 static int
5514 xpm_str_to_color_key (const char *s)
5515 {
5516 int i;
5517
5518 for (i = 0; i < ARRAYELTS (xpm_color_key_strings); i++)
5519 if (strcmp (xpm_color_key_strings[i], s) == 0)
5520 return i;
5521 return -1;
5522 }
5523
5524 static bool
5525 xpm_load_image (struct frame *f,
5526 struct image *img,
5527 const char *contents,
5528 const char *end)
5529 {
5530 const char *s = contents, *beg, *str;
5531 char buffer[BUFSIZ];
5532 int width, height, x, y;
5533 int num_colors, chars_per_pixel;
5534 ptrdiff_t len;
5535 int LA1;
5536 void (*put_color_table) (Lisp_Object, const char *, int, Lisp_Object);
5537 Lisp_Object (*get_color_table) (Lisp_Object, const char *, int);
5538 Lisp_Object frame, color_symbols, color_table;
5539 int best_key;
5540 #if !defined (HAVE_NS)
5541 bool have_mask = false;
5542 #endif
5543 Emacs_Pix_Container ximg = NULL, mask_img = NULL;
5544
5545 #define match() \
5546 LA1 = xpm_scan (&s, end, &beg, &len)
5547
5548 #define expect(TOKEN) \
5549 do \
5550 { \
5551 if (LA1 != (TOKEN)) \
5552 goto failure; \
5553 match (); \
5554 } \
5555 while (0)
5556
5557 #define expect_ident(IDENT) \
5558 if (LA1 == XPM_TK_IDENT \
5559 && strlen ((IDENT)) == len && memcmp ((IDENT), beg, len) == 0) \
5560 match (); \
5561 else \
5562 goto failure
5563
5564 if (!(end - s >= 9 && memcmp (s, "/* XPM */", 9) == 0))
5565 goto failure;
5566 s += 9;
5567 match ();
5568 expect_ident ("static");
5569 expect_ident ("char");
5570 expect ('*');
5571 expect (XPM_TK_IDENT);
5572 expect ('[');
5573 expect (']');
5574 expect ('=');
5575 expect ('{');
5576 expect (XPM_TK_STRING);
5577 if (len >= BUFSIZ)
5578 goto failure;
5579 memcpy (buffer, beg, len);
5580 buffer[len] = '\0';
5581 if (sscanf (buffer, "%d %d %d %d", &width, &height,
5582 &num_colors, &chars_per_pixel) != 4
5583 || width <= 0 || height <= 0
5584 || num_colors <= 0 || chars_per_pixel <= 0)
5585 goto failure;
5586
5587 if (!check_image_size (f, width, height))
5588 {
5589 image_size_error ();
5590 goto failure;
5591 }
5592
5593 if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, 0)
5594 #ifndef HAVE_NS
5595 || !image_create_x_image_and_pixmap (f, img, width, height, 1,
5596 &mask_img, 1)
5597 #endif
5598 )
5599 {
5600 image_error ("Image too large");
5601 goto failure;
5602 }
5603
5604 expect (',');
5605
5606 XSETFRAME (frame, f);
5607 if (!NILP (Fxw_display_color_p (frame)))
5608 best_key = XPM_COLOR_KEY_C;
5609 else if (!NILP (Fx_display_grayscale_p (frame)))
5610 best_key = (XFIXNAT (Fx_display_planes (frame)) > 2
5611 ? XPM_COLOR_KEY_G : XPM_COLOR_KEY_G4);
5612 else
5613 best_key = XPM_COLOR_KEY_M;
5614
5615 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
5616 if (chars_per_pixel == 1)
5617 color_table = xpm_make_color_table_v (&put_color_table,
5618 &get_color_table);
5619 else
5620 color_table = xpm_make_color_table_h (&put_color_table,
5621 &get_color_table);
5622
5623 while (num_colors-- > 0)
5624 {
5625 char *color, *max_color = NULL;
5626 int key, next_key, max_key = 0;
5627 Lisp_Object symbol_color = Qnil, color_val;
5628 Emacs_Color cdef;
5629
5630 expect (XPM_TK_STRING);
5631 if (len <= chars_per_pixel || len >= BUFSIZ + chars_per_pixel)
5632 goto failure;
5633 memcpy (buffer, beg + chars_per_pixel, len - chars_per_pixel);
5634 buffer[len - chars_per_pixel] = '\0';
5635
5636 str = strtok (buffer, " \t");
5637 if (str == NULL)
5638 goto failure;
5639 key = xpm_str_to_color_key (str);
5640 if (key < 0)
5641 goto failure;
5642 do
5643 {
5644 color = strtok (NULL, " \t");
5645 if (color == NULL)
5646 goto failure;
5647
5648 while ((str = strtok (NULL, " \t")) != NULL)
5649 {
5650 next_key = xpm_str_to_color_key (str);
5651 if (next_key >= 0)
5652 break;
5653 color[strlen (color)] = ' ';
5654 }
5655
5656 if (key == XPM_COLOR_KEY_S)
5657 {
5658 if (NILP (symbol_color))
5659 symbol_color = build_string (color);
5660 }
5661 else if (max_key < key && key <= best_key)
5662 {
5663 max_key = key;
5664 max_color = color;
5665 }
5666 key = next_key;
5667 }
5668 while (str);
5669
5670 color_val = Qnil;
5671 if (!NILP (color_symbols) && !NILP (symbol_color))
5672 {
5673 Lisp_Object specified_color = Fassoc (symbol_color, color_symbols, Qnil);
5674
5675 if (CONSP (specified_color) && STRINGP (XCDR (specified_color)))
5676 {
5677 if (xstrcasecmp (SSDATA (XCDR (specified_color)), "None") == 0)
5678 color_val = Qt;
5679 else if (FRAME_TERMINAL (f)->defined_color_hook
5680 (f, SSDATA (XCDR (specified_color)), &cdef, false, false))
5681 color_val
5682 = make_fixnum (lookup_rgb_color (f, cdef.red, cdef.green,
5683 cdef.blue));
5684 }
5685 }
5686 if (NILP (color_val) && max_color)
5687 {
5688 if (xstrcasecmp (max_color, "None") == 0)
5689 color_val = Qt;
5690 else if (FRAME_TERMINAL (f)->defined_color_hook
5691 (f, max_color, &cdef, false, false))
5692 color_val = make_fixnum (lookup_rgb_color (f, cdef.red, cdef.green,
5693 cdef.blue));
5694 }
5695 if (!NILP (color_val))
5696 (*put_color_table) (color_table, beg, chars_per_pixel, color_val);
5697
5698 expect (',');
5699 }
5700
5701 unsigned long frame_fg = FRAME_FOREGROUND_PIXEL (f);
5702 #ifdef USE_CAIRO
5703 {
5704 Emacs_Color color = {.pixel = frame_fg};
5705 FRAME_TERMINAL (f)->query_colors (f, &color, 1);
5706 frame_fg = lookup_rgb_color (f, color.red, color.green, color.blue);
5707 }
5708 #endif
5709 for (y = 0; y < height; y++)
5710 {
5711 expect (XPM_TK_STRING);
5712 str = beg;
5713 if (len < width * chars_per_pixel)
5714 goto failure;
5715 for (x = 0; x < width; x++, str += chars_per_pixel)
5716 {
5717 Lisp_Object color_val =
5718 (*get_color_table) (color_table, str, chars_per_pixel);
5719
5720 PUT_PIXEL (ximg, x, y,
5721 FIXNUMP (color_val) ? XFIXNUM (color_val) : frame_fg);
5722 #ifndef HAVE_NS
5723 PUT_PIXEL (mask_img, x, y,
5724 (!EQ (color_val, Qt) ? PIX_MASK_DRAW
5725 : (have_mask = true, PIX_MASK_RETAIN)));
5726 #else
5727 if (EQ (color_val, Qt))
5728 ns_set_alpha (ximg, x, y, 0);
5729 #endif
5730 }
5731 if (y + 1 < height)
5732 expect (',');
5733 }
5734
5735 img->width = width;
5736 img->height = height;
5737
5738
5739 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
5740 IMAGE_BACKGROUND (img, f, ximg);
5741
5742 image_put_x_image (f, img, ximg, 0);
5743 #ifndef HAVE_NS
5744 if (have_mask)
5745 {
5746
5747
5748 image_background_transparent (img, f, mask_img);
5749
5750 image_put_x_image (f, img, mask_img, 1);
5751 }
5752 else
5753 {
5754 image_destroy_x_image (mask_img);
5755 image_clear_image_1 (f, img, CLEAR_IMAGE_MASK);
5756 }
5757 #endif
5758 return 1;
5759
5760 failure:
5761 image_error ("Invalid XPM3 file (%s)", img->spec);
5762 image_destroy_x_image (ximg);
5763 image_destroy_x_image (mask_img);
5764 image_clear_image (f, img);
5765 return 0;
5766
5767 #undef match
5768 #undef expect
5769 #undef expect_ident
5770 }
5771
5772 static bool
5773 xpm_load (struct frame *f,
5774 struct image *img)
5775 {
5776 bool success_p = 0;
5777 Lisp_Object file_name;
5778
5779
5780 file_name = image_spec_value (img->spec, QCfile, NULL);
5781 if (STRINGP (file_name))
5782 {
5783 int fd;
5784 Lisp_Object file = image_find_image_fd (file_name, &fd);
5785 if (!STRINGP (file))
5786 {
5787 image_error ("Cannot find image file `%s'", file_name);
5788 return 0;
5789 }
5790
5791 ptrdiff_t size;
5792 char *contents = slurp_file (fd, &size);
5793 if (contents == NULL)
5794 {
5795 image_error ("Error loading XPM image `%s'", file);
5796 return 0;
5797 }
5798
5799 success_p = xpm_load_image (f, img, contents, contents + size);
5800 xfree (contents);
5801 }
5802 else
5803 {
5804 Lisp_Object data;
5805
5806 data = image_spec_value (img->spec, QCdata, NULL);
5807 if (!STRINGP (data))
5808 {
5809 image_error ("Invalid image data `%s'", data);
5810 return 0;
5811 }
5812 success_p = xpm_load_image (f, img, SSDATA (data),
5813 SSDATA (data) + SBYTES (data));
5814 }
5815
5816 return success_p;
5817 }
5818
5819 #endif
5820
5821
5822
5823
5824
5825
5826
5827 #ifdef COLOR_TABLE_SUPPORT
5828
5829
5830
5831 struct ct_color
5832 {
5833 int r, g, b;
5834 unsigned long pixel;
5835
5836
5837 struct ct_color *next;
5838 };
5839
5840
5841
5842 #define CT_SIZE 101
5843
5844
5845
5846 static unsigned
5847 ct_hash_rgb (unsigned r, unsigned g, unsigned b)
5848 {
5849 return (r << 16) ^ (g << 8) ^ b;
5850 }
5851
5852
5853
5854 static struct ct_color **ct_table;
5855
5856
5857
5858 static int ct_colors_allocated;
5859 enum
5860 {
5861 ct_colors_allocated_max =
5862 min (INT_MAX,
5863 min (PTRDIFF_MAX, SIZE_MAX) / sizeof (unsigned long))
5864 };
5865
5866
5867
5868 static void
5869 init_color_table (void)
5870 {
5871 int size = CT_SIZE * sizeof (*ct_table);
5872 ct_table = xzalloc (size);
5873 ct_colors_allocated = 0;
5874 }
5875
5876
5877
5878
5879 static void
5880 free_color_table (void)
5881 {
5882 int i;
5883 struct ct_color *p, *next;
5884
5885 for (i = 0; i < CT_SIZE; ++i)
5886 for (p = ct_table[i]; p; p = next)
5887 {
5888 next = p->next;
5889 xfree (p);
5890 }
5891
5892 xfree (ct_table);
5893 ct_table = NULL;
5894 }
5895
5896
5897
5898
5899
5900
5901
5902 static unsigned long
5903 lookup_rgb_color (struct frame *f, int r, int g, int b)
5904 {
5905 unsigned hash = ct_hash_rgb (r, g, b);
5906 int i = hash % CT_SIZE;
5907 struct ct_color *p;
5908 Display_Info *dpyinfo;
5909
5910
5911
5912
5913
5914 dpyinfo = FRAME_DISPLAY_INFO (f);
5915 if (dpyinfo->red_bits > 0)
5916 {
5917
5918 if (f->gamma)
5919 {
5920 XColor color;
5921 color.red = r, color.green = g, color.blue = b;
5922 gamma_correct (f, &color);
5923 r = color.red, g = color.green, b = color.blue;
5924 }
5925
5926 return x_make_truecolor_pixel (dpyinfo, r, g, b);
5927 }
5928
5929 for (p = ct_table[i]; p; p = p->next)
5930 if (p->r == r && p->g == g && p->b == b)
5931 break;
5932
5933 if (p == NULL)
5934 {
5935
5936 #ifdef HAVE_X_WINDOWS
5937 XColor color;
5938 Colormap cmap;
5939 bool rc;
5940 #else
5941 COLORREF color;
5942 #endif
5943
5944 if (ct_colors_allocated_max <= ct_colors_allocated)
5945 return FRAME_FOREGROUND_PIXEL (f);
5946
5947 #ifdef HAVE_X_WINDOWS
5948 color.red = r;
5949 color.green = g;
5950 color.blue = b;
5951
5952 cmap = FRAME_X_COLORMAP (f);
5953 rc = x_alloc_nearest_color (f, cmap, &color);
5954 if (rc)
5955 {
5956 ++ct_colors_allocated;
5957 p = xmalloc (sizeof *p);
5958 p->r = r;
5959 p->g = g;
5960 p->b = b;
5961 p->pixel = color.pixel;
5962 p->next = ct_table[i];
5963 ct_table[i] = p;
5964 }
5965 else
5966 return FRAME_FOREGROUND_PIXEL (f);
5967
5968 #else
5969 #ifdef HAVE_NTGUI
5970 color = PALETTERGB (r, g, b);
5971 #else
5972 color = RGB_TO_ULONG (r, g, b);
5973 #endif
5974 ++ct_colors_allocated;
5975 p = xmalloc (sizeof *p);
5976 p->r = r;
5977 p->g = g;
5978 p->b = b;
5979 p->pixel = color;
5980 p->next = ct_table[i];
5981 ct_table[i] = p;
5982 #endif
5983
5984 }
5985
5986 return p->pixel;
5987 }
5988
5989
5990
5991
5992
5993 static unsigned long
5994 lookup_pixel_color (struct frame *f, unsigned long pixel)
5995 {
5996 int i = pixel % CT_SIZE;
5997 struct ct_color *p;
5998
5999 for (p = ct_table[i]; p; p = p->next)
6000 if (p->pixel == pixel)
6001 break;
6002
6003 if (p == NULL)
6004 {
6005 XColor color;
6006 Colormap cmap;
6007 bool rc;
6008
6009 if (ct_colors_allocated >= ct_colors_allocated_max)
6010 return FRAME_FOREGROUND_PIXEL (f);
6011
6012 #ifdef HAVE_X_WINDOWS
6013 cmap = FRAME_X_COLORMAP (f);
6014 color.pixel = pixel;
6015 x_query_colors (f, &color, 1);
6016 rc = x_alloc_nearest_color (f, cmap, &color);
6017 #else
6018 block_input ();
6019 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
6020 color.pixel = pixel;
6021 XQueryColor (NULL, cmap, &color);
6022 rc = x_alloc_nearest_color (f, cmap, &color);
6023 unblock_input ();
6024 #endif
6025
6026 if (rc)
6027 {
6028 ++ct_colors_allocated;
6029
6030 p = xmalloc (sizeof *p);
6031 p->r = color.red;
6032 p->g = color.green;
6033 p->b = color.blue;
6034 p->pixel = pixel;
6035 p->next = ct_table[i];
6036 ct_table[i] = p;
6037 }
6038 else
6039 return FRAME_FOREGROUND_PIXEL (f);
6040 }
6041 return p->pixel;
6042 }
6043
6044
6045
6046
6047
6048 static unsigned long *
6049 colors_in_color_table (int *n)
6050 {
6051 int i, j;
6052 struct ct_color *p;
6053 unsigned long *colors;
6054
6055 if (ct_colors_allocated == 0)
6056 {
6057 *n = 0;
6058 colors = NULL;
6059 }
6060 else
6061 {
6062 colors = xmalloc (ct_colors_allocated * sizeof *colors);
6063 *n = ct_colors_allocated;
6064
6065 for (i = j = 0; i < CT_SIZE; ++i)
6066 for (p = ct_table[i]; p; p = p->next)
6067 colors[j++] = p->pixel;
6068 }
6069
6070 return colors;
6071 }
6072
6073 #else
6074
6075 static unsigned long
6076 lookup_rgb_color (struct frame *f, int r, int g, int b)
6077 {
6078 #ifdef HAVE_NTGUI
6079 return PALETTERGB (r >> 8, g >> 8, b >> 8);
6080 #elif defined USE_CAIRO || defined HAVE_NS || defined HAVE_HAIKU
6081 return RGB_TO_ULONG (r >> 8, g >> 8, b >> 8);
6082 #else
6083 xsignal1 (Qfile_error,
6084 build_string ("This Emacs mishandles this image file type"));
6085 #endif
6086 }
6087
6088 static void
6089 init_color_table (void)
6090 {
6091 }
6092 #endif
6093
6094
6095
6096
6097
6098
6099
6100
6101
6102 static int emboss_matrix[9] = {
6103
6104 2, -1, 0,
6105 -1, 0, 1,
6106 0, 1, -2
6107 };
6108
6109 static int laplace_matrix[9] = {
6110
6111 1, 0, 0,
6112 0, 0, 0,
6113 0, 0, -1
6114 };
6115
6116
6117
6118
6119 #define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6)
6120
6121
6122
6123
6124
6125
6126
6127
6128 static Emacs_Color *
6129 image_to_emacs_colors (struct frame *f, struct image *img, bool rgb_p)
6130 {
6131 int x, y;
6132 Emacs_Color *colors, *p;
6133 Emacs_Pix_Context ximg;
6134 ptrdiff_t nbytes;
6135 #ifdef HAVE_NTGUI
6136 HGDIOBJ prev;
6137 #endif
6138
6139 if (INT_MULTIPLY_WRAPV (sizeof *colors, img->width, &nbytes)
6140 || INT_MULTIPLY_WRAPV (img->height, nbytes, &nbytes)
6141 || SIZE_MAX < nbytes)
6142 memory_full (SIZE_MAX);
6143 colors = xmalloc (nbytes);
6144
6145
6146 ximg = image_get_x_image_or_dc (f, img, 0, &prev);
6147
6148
6149
6150 p = colors;
6151 for (y = 0; y < img->height; ++y)
6152 {
6153 #if !defined USE_CAIRO && !defined HAVE_NS && !defined HAVE_HAIKU
6154 Emacs_Color *row = p;
6155 for (x = 0; x < img->width; ++x, ++p)
6156 p->pixel = GET_PIXEL (ximg, x, y);
6157 if (rgb_p)
6158 {
6159 FRAME_TERMINAL (f)->query_colors (f, row, img->width);
6160 }
6161 #else
6162 for (x = 0; x < img->width; ++x, ++p)
6163 {
6164 p->pixel = GET_PIXEL (ximg, x, y);
6165 if (rgb_p)
6166 {
6167 p->red = RED16_FROM_ULONG (p->pixel);
6168 p->green = GREEN16_FROM_ULONG (p->pixel);
6169 p->blue = BLUE16_FROM_ULONG (p->pixel);
6170 }
6171 }
6172 #endif
6173 }
6174
6175 image_unget_x_image_or_dc (img, 0, ximg, prev);
6176
6177 return colors;
6178 }
6179
6180 #ifdef HAVE_NTGUI
6181
6182
6183
6184
6185
6186 static void
6187 XPutPixel (XImage *ximg, int x, int y, COLORREF color)
6188 {
6189 int width = ximg->info.bmiHeader.biWidth;
6190 unsigned char * pixel;
6191
6192
6193 if (ximg->info.bmiHeader.biBitCount == 24)
6194 {
6195 int rowbytes = width * 3;
6196
6197 if (rowbytes % 4)
6198 rowbytes += 4 - (rowbytes % 4);
6199
6200 pixel = ximg->data + y * rowbytes + x * 3;
6201
6202 *pixel = GetBValue (color);
6203 *(pixel + 1) = GetGValue (color);
6204 *(pixel + 2) = GetRValue (color);
6205 }
6206
6207 else if (ximg->info.bmiHeader.biBitCount == 1)
6208 {
6209 int rowbytes = width / 8;
6210
6211 if (rowbytes % 4)
6212 rowbytes += 4 - (rowbytes % 4);
6213 pixel = ximg->data + y * rowbytes + x / 8;
6214
6215 if (color & 0x00ffffff)
6216 *pixel = *pixel | (1 << x % 8);
6217 else
6218 *pixel = *pixel & ~(1 << x % 8);
6219 }
6220 else
6221 image_error ("XPutPixel: palette image not supported");
6222 }
6223
6224 #endif
6225
6226
6227
6228
6229
6230 static void
6231 image_from_emacs_colors (struct frame *f, struct image *img, Emacs_Color *colors)
6232 {
6233 int x, y;
6234 Emacs_Pix_Container ximage;
6235 Emacs_Color *p;
6236
6237 ximage = NULL;
6238
6239 init_color_table ();
6240
6241 image_clear_image_1 (f, img, CLEAR_IMAGE_PIXMAP | CLEAR_IMAGE_COLORS);
6242 image_create_x_image_and_pixmap (f, img, img->width, img->height, 0,
6243 &ximage, 0);
6244 p = colors;
6245 for (y = 0; y < img->height; ++y)
6246 for (x = 0; x < img->width; ++x, ++p)
6247 {
6248 unsigned long pixel;
6249 pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
6250 PUT_PIXEL (ximage, x, y, pixel);
6251 }
6252
6253 xfree (colors);
6254
6255 image_put_x_image (f, img, ximage, false);
6256 #ifdef COLOR_TABLE_SUPPORT
6257 img->colors = colors_in_color_table (&img->ncolors);
6258 free_color_table ();
6259 #endif
6260 }
6261
6262
6263
6264
6265
6266
6267
6268
6269
6270
6271 static void
6272 image_detect_edges (struct frame *f, struct image *img,
6273 int *matrix, int color_adjust)
6274 {
6275 Emacs_Color *colors = image_to_emacs_colors (f, img, 1);
6276 Emacs_Color *new, *p;
6277 int x, y, i, sum;
6278 ptrdiff_t nbytes;
6279
6280 for (i = sum = 0; i < 9; ++i)
6281 sum += eabs (matrix[i]);
6282
6283 #define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))
6284
6285 if (INT_MULTIPLY_WRAPV (sizeof *new, img->width, &nbytes)
6286 || INT_MULTIPLY_WRAPV (img->height, nbytes, &nbytes))
6287 memory_full (SIZE_MAX);
6288 new = xmalloc (nbytes);
6289
6290 for (y = 0; y < img->height; ++y)
6291 {
6292 p = COLOR (new, 0, y);
6293 p->red = p->green = p->blue = 0xffff/2;
6294 p = COLOR (new, img->width - 1, y);
6295 p->red = p->green = p->blue = 0xffff/2;
6296 }
6297
6298 for (x = 1; x < img->width - 1; ++x)
6299 {
6300 p = COLOR (new, x, 0);
6301 p->red = p->green = p->blue = 0xffff/2;
6302 p = COLOR (new, x, img->height - 1);
6303 p->red = p->green = p->blue = 0xffff/2;
6304 }
6305
6306 for (y = 1; y < img->height - 1; ++y)
6307 {
6308 p = COLOR (new, 1, y);
6309
6310 for (x = 1; x < img->width - 1; ++x, ++p)
6311 {
6312 int r, g, b, yy, xx;
6313
6314 r = g = b = i = 0;
6315 for (yy = y - 1; yy < y + 2; ++yy)
6316 for (xx = x - 1; xx < x + 2; ++xx, ++i)
6317 if (matrix[i])
6318 {
6319 Emacs_Color *t = COLOR (colors, xx, yy);
6320 r += matrix[i] * t->red;
6321 g += matrix[i] * t->green;
6322 b += matrix[i] * t->blue;
6323 }
6324
6325 r = (r / sum + color_adjust) & 0xffff;
6326 g = (g / sum + color_adjust) & 0xffff;
6327 b = (b / sum + color_adjust) & 0xffff;
6328 p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b);
6329 }
6330 }
6331
6332 xfree (colors);
6333 image_from_emacs_colors (f, img, new);
6334
6335 #undef COLOR
6336 }
6337
6338
6339
6340
6341
6342 static void
6343 image_emboss (struct frame *f, struct image *img)
6344 {
6345 image_detect_edges (f, img, emboss_matrix, 0xffff / 2);
6346 }
6347
6348
6349
6350
6351
6352
6353 static void
6354 image_laplace (struct frame *f, struct image *img)
6355 {
6356 image_detect_edges (f, img, laplace_matrix, 45000);
6357 }
6358
6359
6360
6361
6362
6363
6364
6365
6366
6367
6368
6369
6370
6371 static void
6372 image_edge_detection (struct frame *f, struct image *img,
6373 Lisp_Object matrix, Lisp_Object color_adjust)
6374 {
6375 int i = 0;
6376 int trans[9];
6377
6378 if (CONSP (matrix))
6379 {
6380 for (i = 0;
6381 i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix));
6382 ++i, matrix = XCDR (matrix))
6383 trans[i] = XFLOATINT (XCAR (matrix));
6384 }
6385 else if (VECTORP (matrix) && ASIZE (matrix) >= 9)
6386 {
6387 for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i)
6388 trans[i] = XFLOATINT (AREF (matrix, i));
6389 }
6390
6391 if (NILP (color_adjust))
6392 color_adjust = make_fixnum (0xffff / 2);
6393
6394 if (i == 9 && NUMBERP (color_adjust))
6395 image_detect_edges (f, img, trans, XFLOATINT (color_adjust));
6396 }
6397
6398
6399 #if defined HAVE_X_WINDOWS || defined USE_CAIRO || defined HAVE_HAIKU
6400 static void
6401 image_pixmap_draw_cross (struct frame *f, Emacs_Pixmap pixmap,
6402 int x, int y, unsigned int width, unsigned int height,
6403 unsigned long color)
6404 {
6405 #ifdef USE_CAIRO
6406 cairo_surface_t *surface
6407 = cairo_image_surface_create_for_data ((unsigned char *) pixmap->data,
6408 (pixmap->bits_per_pixel == 32
6409 ? CAIRO_FORMAT_RGB24
6410 : CAIRO_FORMAT_A8),
6411 pixmap->width, pixmap->height,
6412 pixmap->bytes_per_line);
6413 cairo_t *cr = cairo_create (surface);
6414 cairo_surface_destroy (surface);
6415 cairo_set_source_rgb (cr, RED_FROM_ULONG (color) / 255.0,
6416 GREEN_FROM_ULONG (color) / 255.0,
6417 BLUE_FROM_ULONG (color) / 255.0);
6418 cairo_move_to (cr, x + 0.5, y + 0.5);
6419 cairo_rel_line_to (cr, width - 1, height - 1);
6420 cairo_rel_move_to (cr, 0, - (height - 1));
6421 cairo_rel_line_to (cr, - (width - 1), height - 1);
6422 cairo_set_line_width (cr, 1);
6423 cairo_stroke (cr);
6424 cairo_destroy (cr);
6425 #elif HAVE_X_WINDOWS
6426 Display *dpy = FRAME_X_DISPLAY (f);
6427 GC gc = XCreateGC (dpy, pixmap, 0, NULL);
6428
6429 XSetForeground (dpy, gc, color);
6430 XDrawLine (dpy, pixmap, gc, x, y, x + width - 1, y + height - 1);
6431 XDrawLine (dpy, pixmap, gc, x, y + height - 1, x + width - 1, y);
6432 XFreeGC (dpy, gc);
6433 #elif HAVE_HAIKU
6434 be_draw_cross_on_pixmap (pixmap, x, y, width, height, color);
6435 #endif
6436 }
6437 #endif
6438
6439
6440
6441 static void
6442 image_disable_image (struct frame *f, struct image *img)
6443 {
6444 Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
6445 #ifdef HAVE_NTGUI
6446 int n_planes = dpyinfo->n_planes * dpyinfo->n_cbits;
6447 #else
6448 int n_planes = dpyinfo->n_planes;
6449 #endif
6450
6451 if (n_planes >= 2)
6452 {
6453
6454
6455
6456 Emacs_Color *colors = image_to_emacs_colors (f, img, 1);
6457 Emacs_Color *p, *end;
6458 const int h = 15000;
6459 const int l = 30000;
6460
6461 for (p = colors, end = colors + img->width * img->height;
6462 p < end;
6463 ++p)
6464 {
6465 int i = COLOR_INTENSITY (p->red, p->green, p->blue);
6466 int i2 = (0xffff - h - l) * i / 0xffff + l;
6467 p->red = p->green = p->blue = i2;
6468 }
6469
6470 image_from_emacs_colors (f, img, colors);
6471 }
6472
6473
6474
6475 if (n_planes < 2 || cross_disabled_images)
6476 {
6477 #ifndef HAVE_NTGUI
6478 #ifndef HAVE_NS
6479
6480 #if !defined USE_CAIRO && !defined HAVE_HAIKU
6481 #define CrossForeground(f) BLACK_PIX_DEFAULT (f)
6482 #define MaskForeground(f) WHITE_PIX_DEFAULT (f)
6483 #else
6484 #define CrossForeground(f) 0
6485 #define MaskForeground(f) PIX_MASK_DRAW
6486 #endif
6487
6488 #if !defined USE_CAIRO && !defined HAVE_HAIKU
6489 image_sync_to_pixmaps (f, img);
6490 #endif
6491 image_pixmap_draw_cross (f, img->pixmap, 0, 0, img->width, img->height,
6492 CrossForeground (f));
6493 if (img->mask)
6494 image_pixmap_draw_cross (f, img->mask, 0, 0, img->width, img->height,
6495 MaskForeground (f));
6496 #endif
6497 #else
6498 HDC hdc, bmpdc;
6499 HGDIOBJ prev;
6500
6501 hdc = get_frame_dc (f);
6502 bmpdc = CreateCompatibleDC (hdc);
6503 release_frame_dc (f, hdc);
6504
6505 prev = SelectObject (bmpdc, img->pixmap);
6506
6507 SetTextColor (bmpdc, BLACK_PIX_DEFAULT (f));
6508 MoveToEx (bmpdc, 0, 0, NULL);
6509 LineTo (bmpdc, img->width - 1, img->height - 1);
6510 MoveToEx (bmpdc, 0, img->height - 1, NULL);
6511 LineTo (bmpdc, img->width - 1, 0);
6512
6513 if (img->mask)
6514 {
6515 SelectObject (bmpdc, img->mask);
6516 SetTextColor (bmpdc, WHITE_PIX_DEFAULT (f));
6517 MoveToEx (bmpdc, 0, 0, NULL);
6518 LineTo (bmpdc, img->width - 1, img->height - 1);
6519 MoveToEx (bmpdc, 0, img->height - 1, NULL);
6520 LineTo (bmpdc, img->width - 1, 0);
6521 }
6522 SelectObject (bmpdc, prev);
6523 DeleteDC (bmpdc);
6524 #endif
6525 }
6526 }
6527
6528
6529
6530
6531
6532
6533
6534
6535
6536 static void
6537 image_build_heuristic_mask (struct frame *f, struct image *img,
6538 Lisp_Object how)
6539 {
6540 Emacs_Pix_Context ximg;
6541 #ifdef HAVE_NTGUI
6542 HGDIOBJ prev;
6543 char *mask_img;
6544 int row_width;
6545 #elif !defined HAVE_NS
6546 Emacs_Pix_Container mask_img;
6547 #endif
6548 int x, y;
6549 bool use_img_background;
6550 unsigned long bg = 0;
6551
6552 if (img->mask)
6553 image_clear_image_1 (f, img, CLEAR_IMAGE_MASK);
6554
6555 #ifndef HAVE_NTGUI
6556 #ifndef HAVE_NS
6557
6558 if (! image_create_x_image_and_pixmap (f, img, img->width, img->height, 1,
6559 &mask_img, 1))
6560 return;
6561 #endif
6562 #else
6563
6564 row_width = (img->width + 7) / 8;
6565 mask_img = xzalloc (row_width * img->height);
6566 #endif
6567
6568
6569 ximg = image_get_x_image_or_dc (f, img, 0, &prev);
6570
6571
6572
6573 use_img_background = 1;
6574
6575 if (CONSP (how))
6576 {
6577 int rgb[3], i;
6578
6579 for (i = 0; i < 3 && CONSP (how) && FIXNATP (XCAR (how)); ++i)
6580 {
6581 rgb[i] = XFIXNAT (XCAR (how)) & 0xffff;
6582 how = XCDR (how);
6583 }
6584
6585 if (i == 3 && NILP (how))
6586 {
6587 #ifndef USE_CAIRO
6588 char color_name[30];
6589 sprintf (color_name, "#%04x%04x%04x",
6590 rgb[0] + 0u, rgb[1] + 0u, rgb[2] + 0u);
6591 bg = (
6592 #ifdef HAVE_NTGUI
6593 0x00ffffff &
6594 #endif
6595 image_alloc_image_color (f, img, build_string (color_name), 0));
6596 #else
6597 bg = lookup_rgb_color (f, rgb[0], rgb[1], rgb[2]);
6598 #endif
6599 use_img_background = 0;
6600 }
6601 }
6602
6603 if (use_img_background)
6604 bg = four_corners_best (ximg, img->corners, img->width, img->height);
6605
6606
6607
6608 #ifndef HAVE_NTGUI
6609 for (y = 0; y < img->height; ++y)
6610 for (x = 0; x < img->width; ++x)
6611 #ifndef HAVE_NS
6612 PUT_PIXEL (mask_img, x, y, (GET_PIXEL (ximg, x, y) != bg
6613 ? PIX_MASK_DRAW : PIX_MASK_RETAIN));
6614 #else
6615 if (XGetPixel (ximg, x, y) == bg)
6616 ns_set_alpha (ximg, x, y, 0);
6617 #endif
6618 #ifndef HAVE_NS
6619
6620 image_background_transparent (img, f, mask_img);
6621
6622
6623 image_put_x_image (f, img, mask_img, 1);
6624 #endif
6625 #else
6626 for (y = 0; y < img->height; ++y)
6627 for (x = 0; x < img->width; ++x)
6628 {
6629 COLORREF p = GetPixel (ximg, x, y);
6630 if (p != bg)
6631 mask_img[y * row_width + x / 8] |= 1 << (x % 8);
6632 }
6633
6634
6635 img->mask = w32_create_pixmap_from_bitmap_data (img->width, img->height,
6636 mask_img);
6637
6638 SelectObject (ximg, img->mask);
6639 image_background_transparent (img, f, ximg);
6640
6641
6642 xfree (mask_img);
6643 #endif
6644
6645 image_unget_x_image_or_dc (img, 0, ximg, prev);
6646 }
6647
6648
6649
6650
6651
6652
6653
6654
6655 enum pbm_keyword_index
6656 {
6657 PBM_TYPE,
6658 PBM_FILE,
6659 PBM_DATA,
6660 PBM_ASCENT,
6661 PBM_MARGIN,
6662 PBM_RELIEF,
6663 PBM_ALGORITHM,
6664 PBM_HEURISTIC_MASK,
6665 PBM_MASK,
6666 PBM_FOREGROUND,
6667 PBM_BACKGROUND,
6668 PBM_LAST
6669 };
6670
6671
6672
6673
6674 static const struct image_keyword pbm_format[PBM_LAST] =
6675 {
6676 {":type", IMAGE_SYMBOL_VALUE, 1},
6677 {":file", IMAGE_STRING_VALUE, 0},
6678 {":data", IMAGE_STRING_VALUE, 0},
6679 {":ascent", IMAGE_ASCENT_VALUE, 0},
6680 {":margin", IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR, 0},
6681 {":relief", IMAGE_INTEGER_VALUE, 0},
6682 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6683 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6684 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6685 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
6686 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6687 };
6688
6689
6690
6691 static bool
6692 pbm_image_p (Lisp_Object object)
6693 {
6694 struct image_keyword fmt[PBM_LAST];
6695
6696 memcpy (fmt, pbm_format, sizeof fmt);
6697
6698 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm))
6699 return 0;
6700
6701
6702 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
6703 }
6704
6705
6706
6707
6708
6709 static int
6710 pbm_next_char (char **s, char *end)
6711 {
6712 while (*s < end)
6713 {
6714 unsigned char c = *(*s)++;
6715 if (c != '#')
6716 return c;
6717 while (*s < end)
6718 {
6719 c = *(*s)++;
6720 if (c == '\n' || c == '\r')
6721 break;
6722 }
6723 }
6724
6725 return -1;
6726 }
6727
6728
6729
6730
6731
6732
6733 static int
6734 pbm_scan_number (char **s, char *end)
6735 {
6736 int c = 0, val = -1;
6737
6738
6739 while ((c = pbm_next_char (s, end)) != -1 && c_isspace (c))
6740 ;
6741
6742 if (c_isdigit (c))
6743 {
6744
6745 val = c - '0';
6746 while ((c = pbm_next_char (s, end)) != -1 && c_isdigit (c))
6747 val = 10 * val + c - '0';
6748 }
6749
6750 return val;
6751 }
6752
6753
6754
6755
6756
6757 static int
6758 pbm_scan_index (char **s, bool two_byte)
6759 {
6760 char *p = *s;
6761 unsigned char c0 = *p++;
6762 int n = c0;
6763 if (two_byte)
6764 {
6765 unsigned char c1 = *p++;
6766 n = (n << 8) + c1;
6767 }
6768 *s = p;
6769 return n;
6770 }
6771
6772
6773
6774
6775 static bool
6776 pbm_load (struct frame *f, struct image *img)
6777 {
6778 bool raw_p;
6779 int x, y;
6780 int width, height, max_color_idx = 0;
6781 Lisp_Object specified_file;
6782 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
6783 char *contents = NULL;
6784 char *end, *p;
6785 Emacs_Pix_Container ximg;
6786
6787 specified_file = image_spec_value (img->spec, QCfile, NULL);
6788
6789 if (STRINGP (specified_file))
6790 {
6791 int fd;
6792 Lisp_Object file = image_find_image_fd (specified_file, &fd);
6793 if (!STRINGP (file))
6794 {
6795 image_error ("Cannot find image file `%s'", specified_file);
6796 return 0;
6797 }
6798
6799 ptrdiff_t size;
6800 contents = slurp_file (fd, &size);
6801 if (contents == NULL)
6802 {
6803 image_error ("Error reading `%s'", file);
6804 return 0;
6805 }
6806
6807 p = contents;
6808 end = contents + size;
6809 }
6810 else
6811 {
6812 Lisp_Object data;
6813 data = image_spec_value (img->spec, QCdata, NULL);
6814 if (!STRINGP (data))
6815 {
6816 image_error ("Invalid image data `%s'", data);
6817 return 0;
6818 }
6819 p = SSDATA (data);
6820 end = p + SBYTES (data);
6821 }
6822
6823
6824 if (end - p < 2 || *p++ != 'P')
6825 {
6826 image_error ("Not a PBM image: `%s'", img->spec);
6827 error:
6828 xfree (contents);
6829 img->pixmap = NO_PIXMAP;
6830 return 0;
6831 }
6832
6833 switch (*p++)
6834 {
6835 case '1':
6836 raw_p = 0, type = PBM_MONO;
6837 break;
6838
6839 case '2':
6840 raw_p = 0, type = PBM_GRAY;
6841 break;
6842
6843 case '3':
6844 raw_p = 0, type = PBM_COLOR;
6845 break;
6846
6847 case '4':
6848 raw_p = 1, type = PBM_MONO;
6849 break;
6850
6851 case '5':
6852 raw_p = 1, type = PBM_GRAY;
6853 break;
6854
6855 case '6':
6856 raw_p = 1, type = PBM_COLOR;
6857 break;
6858
6859 default:
6860 image_error ("Not a PBM image: `%s'", img->spec);
6861 goto error;
6862 }
6863
6864
6865
6866 width = pbm_scan_number (&p, end);
6867 height = pbm_scan_number (&p, end);
6868
6869 if (type != PBM_MONO)
6870 {
6871 max_color_idx = pbm_scan_number (&p, end);
6872 if (max_color_idx > 65535 || max_color_idx < 0)
6873 {
6874 image_error ("Unsupported maximum PBM color value");
6875 goto error;
6876 }
6877 }
6878
6879 if (!check_image_size (f, width, height))
6880 {
6881 image_size_error ();
6882 goto error;
6883 }
6884
6885 if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, 0))
6886 goto error;
6887
6888
6889 init_color_table ();
6890
6891 if (type == PBM_MONO)
6892 {
6893 unsigned char c = 0;
6894 int g;
6895 struct image_keyword fmt[PBM_LAST];
6896 unsigned long fg = img->face_foreground;
6897 unsigned long bg = img->face_background;
6898
6899 memcpy (fmt, pbm_format, sizeof fmt);
6900 parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
6901
6902
6903 if (fmt[PBM_FOREGROUND].count
6904 && STRINGP (fmt[PBM_FOREGROUND].value))
6905 fg = image_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
6906 if (fmt[PBM_BACKGROUND].count
6907 && STRINGP (fmt[PBM_BACKGROUND].value))
6908 {
6909 bg = image_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg);
6910 img->background = bg;
6911 img->background_valid = 1;
6912 }
6913
6914 #ifdef USE_CAIRO
6915 {
6916 Emacs_Color fgbg[] = {{.pixel = fg}, {.pixel = bg}};
6917 FRAME_TERMINAL (f)->query_colors (f, fgbg, ARRAYELTS (fgbg));
6918 fg = lookup_rgb_color (f, fgbg[0].red, fgbg[0].green, fgbg[0].blue);
6919 bg = lookup_rgb_color (f, fgbg[1].red, fgbg[1].green, fgbg[1].blue);
6920 }
6921 #endif
6922 for (y = 0; y < height; ++y)
6923 for (x = 0; x < width; ++x)
6924 {
6925 if (raw_p)
6926 {
6927 if ((x & 7) == 0)
6928 {
6929 if (p >= end)
6930 {
6931 image_destroy_x_image (ximg);
6932 image_clear_image (f, img);
6933 image_error ("Invalid image size in image `%s'",
6934 img->spec);
6935 goto error;
6936 }
6937 c = *p++;
6938 }
6939 g = c & 0x80;
6940 c <<= 1;
6941 }
6942 else
6943 {
6944 int c = 0;
6945
6946 while ((c = pbm_next_char (&p, end)) != -1 && c_isspace (c))
6947 ;
6948
6949 if (c == '0' || c == '1')
6950 g = c - '0';
6951 else
6952 g = 0;
6953 }
6954
6955 PUT_PIXEL (ximg, x, y, g ? fg : bg);
6956 }
6957 }
6958 else
6959 {
6960 int expected_size = height * width;
6961 bool two_byte = 255 < max_color_idx;
6962 if (two_byte)
6963 expected_size *= 2;
6964 if (type == PBM_COLOR)
6965 expected_size *= 3;
6966
6967 if (raw_p && p + expected_size > end)
6968 {
6969 image_destroy_x_image (ximg);
6970 image_clear_image (f, img);
6971 image_error ("Invalid image size in image `%s'", img->spec);
6972 goto error;
6973 }
6974
6975 for (y = 0; y < height; ++y)
6976 for (x = 0; x < width; ++x)
6977 {
6978 int r, g, b;
6979
6980 if (type == PBM_GRAY && raw_p)
6981 r = g = b = pbm_scan_index (&p, two_byte);
6982 else if (type == PBM_GRAY)
6983 r = g = b = pbm_scan_number (&p, end);
6984 else if (raw_p)
6985 {
6986 r = pbm_scan_index (&p, two_byte);
6987 g = pbm_scan_index (&p, two_byte);
6988 b = pbm_scan_index (&p, two_byte);
6989 }
6990 else
6991 {
6992 r = pbm_scan_number (&p, end);
6993 g = pbm_scan_number (&p, end);
6994 b = pbm_scan_number (&p, end);
6995 }
6996
6997 if (r < 0 || g < 0 || b < 0)
6998 {
6999 image_destroy_x_image (ximg);
7000 image_error ("Invalid pixel value in image `%s'", img->spec);
7001 goto error;
7002 }
7003
7004
7005
7006 r = (double) r * 65535 / max_color_idx;
7007 g = (double) g * 65535 / max_color_idx;
7008 b = (double) b * 65535 / max_color_idx;
7009 PUT_PIXEL (ximg, x, y, lookup_rgb_color (f, r, g, b));
7010 }
7011 }
7012
7013 #ifdef COLOR_TABLE_SUPPORT
7014
7015
7016 img->colors = colors_in_color_table (&img->ncolors);
7017 free_color_table ();
7018 #endif
7019
7020 img->width = width;
7021 img->height = height;
7022
7023
7024
7025 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
7026
7027 IMAGE_BACKGROUND (img, f, (Emacs_Pix_Context)ximg);
7028
7029
7030 image_put_x_image (f, img, ximg, 0);
7031
7032
7033
7034
7035
7036 xfree (contents);
7037 return 1;
7038 }
7039
7040
7041
7042
7043
7044
7045 #if HAVE_NATIVE_IMAGE_API
7046 static bool
7047 image_can_use_native_api (Lisp_Object type)
7048 {
7049 # ifdef HAVE_NTGUI
7050 return w32_can_use_native_image_api (type);
7051 # elif defined HAVE_NS
7052 return ns_can_use_native_image_api (type);
7053 # elif defined HAVE_HAIKU
7054 return haiku_can_use_native_image_api (type);
7055 # else
7056 return false;
7057 # endif
7058 }
7059
7060
7061
7062
7063
7064
7065
7066 enum native_image_keyword_index
7067 {
7068 NATIVE_IMAGE_TYPE,
7069 NATIVE_IMAGE_DATA,
7070 NATIVE_IMAGE_FILE,
7071 NATIVE_IMAGE_ASCENT,
7072 NATIVE_IMAGE_MARGIN,
7073 NATIVE_IMAGE_RELIEF,
7074 NATIVE_IMAGE_ALGORITHM,
7075 NATIVE_IMAGE_HEURISTIC_MASK,
7076 NATIVE_IMAGE_MASK,
7077 NATIVE_IMAGE_BACKGROUND,
7078 NATIVE_IMAGE_INDEX,
7079 NATIVE_IMAGE_LAST
7080 };
7081
7082
7083
7084 static const struct image_keyword native_image_format[] =
7085 {
7086 {":type", IMAGE_SYMBOL_VALUE, 1},
7087 {":data", IMAGE_STRING_VALUE, 0},
7088 {":file", IMAGE_STRING_VALUE, 0},
7089 {":ascent", IMAGE_ASCENT_VALUE, 0},
7090 {":margin", IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR, 0},
7091 {":relief", IMAGE_INTEGER_VALUE, 0},
7092 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7093 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7094 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7095 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
7096 {":index", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}
7097 };
7098
7099
7100
7101 static bool
7102 native_image_p (Lisp_Object object)
7103 {
7104 struct image_keyword fmt[NATIVE_IMAGE_LAST];
7105 memcpy (fmt, native_image_format, sizeof fmt);
7106
7107 if (!parse_image_spec (object, fmt, 10, Qnative_image))
7108 return 0;
7109
7110
7111 return fmt[NATIVE_IMAGE_FILE].count + fmt[NATIVE_IMAGE_DATA].count == 1;
7112 }
7113
7114 static bool
7115 native_image_load (struct frame *f, struct image *img)
7116 {
7117 Lisp_Object image_file = image_spec_value (img->spec, QCfile, NULL);
7118
7119 if (STRINGP (image_file))
7120 image_file = image_find_image_file (image_file);
7121
7122 # ifdef HAVE_NTGUI
7123 return w32_load_image (f, img, image_file,
7124 image_spec_value (img->spec, QCdata, NULL));
7125 # elif defined HAVE_NS
7126 return ns_load_image (f, img, image_file,
7127 image_spec_value (img->spec, QCdata, NULL));
7128 # elif defined HAVE_HAIKU
7129 return haiku_load_image (f, img, image_file,
7130 image_spec_value (img->spec, QCdata, NULL));
7131 # else
7132 return 0;
7133 # endif
7134 }
7135
7136 #endif
7137
7138
7139
7140
7141
7142
7143 #if defined (HAVE_PNG)
7144
7145
7146
7147 enum png_keyword_index
7148 {
7149 PNG_TYPE,
7150 PNG_DATA,
7151 PNG_FILE,
7152 PNG_ASCENT,
7153 PNG_MARGIN,
7154 PNG_RELIEF,
7155 PNG_ALGORITHM,
7156 PNG_HEURISTIC_MASK,
7157 PNG_MASK,
7158 PNG_BACKGROUND,
7159 PNG_LAST
7160 };
7161
7162
7163
7164
7165 static const struct image_keyword png_format[PNG_LAST] =
7166 {
7167 {":type", IMAGE_SYMBOL_VALUE, 1},
7168 {":data", IMAGE_STRING_VALUE, 0},
7169 {":file", IMAGE_STRING_VALUE, 0},
7170 {":ascent", IMAGE_ASCENT_VALUE, 0},
7171 {":margin", IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR, 0},
7172 {":relief", IMAGE_INTEGER_VALUE, 0},
7173 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7174 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7175 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7176 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
7177 };
7178
7179
7180
7181 static bool
7182 png_image_p (Lisp_Object object)
7183 {
7184 struct image_keyword fmt[PNG_LAST];
7185 memcpy (fmt, png_format, sizeof fmt);
7186
7187 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng))
7188 return 0;
7189
7190
7191 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
7192 }
7193
7194 #endif
7195
7196
7197 #ifdef HAVE_PNG
7198
7199 # ifdef WINDOWSNT
7200
7201
7202 DEF_DLL_FN (png_voidp, png_get_io_ptr, (png_structp));
7203 DEF_DLL_FN (int, png_sig_cmp, (png_bytep, png_size_t, png_size_t));
7204 DEF_DLL_FN (png_structp, png_create_read_struct,
7205 (png_const_charp, png_voidp, png_error_ptr, png_error_ptr));
7206 DEF_DLL_FN (png_infop, png_create_info_struct, (png_structp));
7207 DEF_DLL_FN (void, png_destroy_read_struct,
7208 (png_structpp, png_infopp, png_infopp));
7209 DEF_DLL_FN (void, png_set_read_fn, (png_structp, png_voidp, png_rw_ptr));
7210 DEF_DLL_FN (void, png_set_sig_bytes, (png_structp, int));
7211 DEF_DLL_FN (void, png_read_info, (png_structp, png_infop));
7212 DEF_DLL_FN (png_uint_32, png_get_IHDR,
7213 (png_structp, png_infop, png_uint_32 *, png_uint_32 *,
7214 int *, int *, int *, int *, int *));
7215 # ifdef PNG_tRNS_SUPPORTED
7216 DEF_DLL_FN (png_uint_32, png_get_tRNS, (png_structp, png_infop, png_bytep *,
7217 int *, png_color_16p *));
7218 # endif
7219 DEF_DLL_FN (void, png_set_strip_16, (png_structp));
7220 DEF_DLL_FN (void, png_set_expand, (png_structp));
7221 DEF_DLL_FN (void, png_set_gray_to_rgb, (png_structp));
7222 DEF_DLL_FN (int, png_set_interlace_handling, (png_structp));
7223 DEF_DLL_FN (void, png_set_background,
7224 (png_structp, png_color_16p, int, int, double));
7225 DEF_DLL_FN (png_uint_32, png_get_bKGD,
7226 (png_structp, png_infop, png_color_16p *));
7227 DEF_DLL_FN (void, png_read_update_info, (png_structp, png_infop));
7228 DEF_DLL_FN (png_byte, png_get_channels, (png_structp, png_infop));
7229 DEF_DLL_FN (png_size_t, png_get_rowbytes, (png_structp, png_infop));
7230 DEF_DLL_FN (void, png_read_image, (png_structp, png_bytepp));
7231 DEF_DLL_FN (void, png_read_end, (png_structp, png_infop));
7232 DEF_DLL_FN (void, png_error, (png_structp, png_const_charp));
7233
7234 # if (PNG_LIBPNG_VER >= 10500)
7235 DEF_DLL_FN (void, png_longjmp, (png_structp, int) PNG_NORETURN);
7236 DEF_DLL_FN (jmp_buf *, png_set_longjmp_fn,
7237 (png_structp, png_longjmp_ptr, size_t));
7238 # endif
7239
7240 static bool
7241 init_png_functions (void)
7242 {
7243 HMODULE library;
7244
7245 if (!(library = w32_delayed_load (Qpng)))
7246 return 0;
7247
7248 LOAD_DLL_FN (library, png_get_io_ptr);
7249 LOAD_DLL_FN (library, png_sig_cmp);
7250 LOAD_DLL_FN (library, png_create_read_struct);
7251 LOAD_DLL_FN (library, png_create_info_struct);
7252 LOAD_DLL_FN (library, png_destroy_read_struct);
7253 LOAD_DLL_FN (library, png_set_read_fn);
7254 LOAD_DLL_FN (library, png_set_sig_bytes);
7255 LOAD_DLL_FN (library, png_read_info);
7256 LOAD_DLL_FN (library, png_get_IHDR);
7257 # ifdef PNG_tRNS_SUPPORTED
7258 LOAD_DLL_FN (library, png_get_tRNS);
7259 # endif
7260 LOAD_DLL_FN (library, png_set_strip_16);
7261 LOAD_DLL_FN (library, png_set_expand);
7262 LOAD_DLL_FN (library, png_set_gray_to_rgb);
7263 LOAD_DLL_FN (library, png_set_interlace_handling);
7264 LOAD_DLL_FN (library, png_set_background);
7265 LOAD_DLL_FN (library, png_get_bKGD);
7266 LOAD_DLL_FN (library, png_read_update_info);
7267 LOAD_DLL_FN (library, png_get_channels);
7268 LOAD_DLL_FN (library, png_get_rowbytes);
7269 LOAD_DLL_FN (library, png_read_image);
7270 LOAD_DLL_FN (library, png_read_end);
7271 LOAD_DLL_FN (library, png_error);
7272
7273 # if (PNG_LIBPNG_VER >= 10500)
7274 LOAD_DLL_FN (library, png_longjmp);
7275 LOAD_DLL_FN (library, png_set_longjmp_fn);
7276 # endif
7277
7278 return 1;
7279 }
7280
7281 # undef png_create_info_struct
7282 # undef png_create_read_struct
7283 # undef png_destroy_read_struct
7284 # undef png_error
7285 # undef png_get_bKGD
7286 # undef png_get_channels
7287 # undef png_get_IHDR
7288 # undef png_get_io_ptr
7289 # undef png_get_rowbytes
7290 # undef png_get_tRNS
7291 # undef png_longjmp
7292 # undef png_read_end
7293 # undef png_read_image
7294 # undef png_read_info
7295 # undef png_read_update_info
7296 # undef png_set_background
7297 # undef png_set_expand
7298 # undef png_set_gray_to_rgb
7299 # undef png_set_interlace_handling
7300 # undef png_set_longjmp_fn
7301 # undef png_set_read_fn
7302 # undef png_set_sig_bytes
7303 # undef png_set_strip_16
7304 # undef png_sig_cmp
7305
7306 # define png_create_info_struct fn_png_create_info_struct
7307 # define png_create_read_struct fn_png_create_read_struct
7308 # define png_destroy_read_struct fn_png_destroy_read_struct
7309 # define png_error fn_png_error
7310 # define png_get_bKGD fn_png_get_bKGD
7311 # define png_get_channels fn_png_get_channels
7312 # define png_get_IHDR fn_png_get_IHDR
7313 # define png_get_io_ptr fn_png_get_io_ptr
7314 # define png_get_rowbytes fn_png_get_rowbytes
7315 # define png_get_tRNS fn_png_get_tRNS
7316 # define png_longjmp fn_png_longjmp
7317 # define png_read_end fn_png_read_end
7318 # define png_read_image fn_png_read_image
7319 # define png_read_info fn_png_read_info
7320 # define png_read_update_info fn_png_read_update_info
7321 # define png_set_background fn_png_set_background
7322 # define png_set_expand fn_png_set_expand
7323 # define png_set_gray_to_rgb fn_png_set_gray_to_rgb
7324 # define png_set_interlace_handling fn_png_set_interlace_handling
7325 # define png_set_longjmp_fn fn_png_set_longjmp_fn
7326 # define png_set_read_fn fn_png_set_read_fn
7327 # define png_set_sig_bytes fn_png_set_sig_bytes
7328 # define png_set_strip_16 fn_png_set_strip_16
7329 # define png_sig_cmp fn_png_sig_cmp
7330
7331 # endif
7332
7333
7334
7335
7336
7337 # ifdef HAVE__SETJMP
7338 # define FAST_SETJMP(j) _setjmp (j)
7339 # define FAST_LONGJMP _longjmp
7340 # else
7341 # define FAST_SETJMP(j) setjmp (j)
7342 # define FAST_LONGJMP longjmp
7343 # endif
7344
7345 # if PNG_LIBPNG_VER < 10500
7346 # define PNG_LONGJMP(ptr) FAST_LONGJMP ((ptr)->jmpbuf, 1)
7347 # define PNG_JMPBUF(ptr) ((ptr)->jmpbuf)
7348 # else
7349
7350 # define PNG_LONGJMP(ptr) png_longjmp (ptr, 1)
7351 # define PNG_JMPBUF(ptr) \
7352 (*png_set_longjmp_fn (ptr, FAST_LONGJMP, sizeof (jmp_buf)))
7353 # endif
7354
7355
7356
7357
7358 static AVOID
7359 my_png_error (png_struct *png_ptr, const char *msg)
7360 {
7361 eassert (png_ptr != NULL);
7362
7363
7364 image_error ("PNG error: %s", build_string (msg));
7365 PNG_LONGJMP (png_ptr);
7366 }
7367
7368
7369 static void
7370 my_png_warning (png_struct *png_ptr, const char *msg)
7371 {
7372 eassert (png_ptr != NULL);
7373 image_error ("PNG warning: %s", build_string (msg));
7374 }
7375
7376
7377
7378 struct png_memory_storage
7379 {
7380 unsigned char *bytes;
7381 ptrdiff_t len;
7382 ptrdiff_t index;
7383 };
7384
7385
7386
7387
7388
7389
7390 static void
7391 png_read_from_memory (png_structp png_ptr, png_bytep data, png_size_t length)
7392 {
7393 struct png_memory_storage *tbr = png_get_io_ptr (png_ptr);
7394
7395 if (length > tbr->len - tbr->index)
7396 png_error (png_ptr, "Read error");
7397
7398 memcpy (data, tbr->bytes + tbr->index, length);
7399 tbr->index = tbr->index + length;
7400 }
7401
7402
7403
7404
7405
7406
7407 static void
7408 png_read_from_file (png_structp png_ptr, png_bytep data, png_size_t length)
7409 {
7410 FILE *fp = png_get_io_ptr (png_ptr);
7411
7412 if (fread (data, 1, length, fp) < length)
7413 png_error (png_ptr, "Read error");
7414 }
7415
7416
7417
7418
7419
7420 struct png_load_context
7421 {
7422
7423 png_struct *png_ptr;
7424 png_info *info_ptr;
7425 png_info *end_info;
7426 FILE *fp;
7427 png_byte *pixels;
7428 png_byte **rows;
7429 };
7430
7431 static bool
7432 png_load_body (struct frame *f, struct image *img, struct png_load_context *c)
7433 {
7434 Lisp_Object specified_file, specified_data;
7435 FILE *fp = NULL;
7436 int x, y;
7437 ptrdiff_t i;
7438 png_struct *png_ptr;
7439 png_info *info_ptr = NULL, *end_info = NULL;
7440 png_byte sig[8];
7441 png_byte *pixels = NULL;
7442 png_byte **rows = NULL;
7443 png_uint_32 width, height;
7444 int bit_depth, color_type, interlace_type;
7445 png_byte channels;
7446 png_uint_32 row_bytes;
7447 bool transparent_p;
7448 struct png_memory_storage tbr;
7449 ptrdiff_t nbytes;
7450 Emacs_Pix_Container ximg, mask_img = NULL;
7451
7452
7453 specified_file = image_spec_value (img->spec, QCfile, NULL);
7454 specified_data = image_spec_value (img->spec, QCdata, NULL);
7455
7456 if (NILP (specified_data))
7457 {
7458 int fd;
7459 Lisp_Object file = image_find_image_fd (specified_file, &fd);
7460 if (!STRINGP (file))
7461 {
7462 image_error ("Cannot find image file `%s'", specified_file);
7463 return 0;
7464 }
7465
7466
7467 fp = fdopen (fd, "rb");
7468 if (!fp)
7469 {
7470 image_error ("Cannot open image file `%s'", file);
7471 return 0;
7472 }
7473
7474
7475 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
7476 || png_sig_cmp (sig, 0, sizeof sig))
7477 {
7478 fclose (fp);
7479 image_error ("Not a PNG file: `%s'", file);
7480 return 0;
7481 }
7482 }
7483 else
7484 {
7485 if (!STRINGP (specified_data))
7486 {
7487 image_error ("Invalid image data `%s'", specified_data);
7488 return 0;
7489 }
7490
7491
7492 tbr.bytes = SDATA (specified_data);
7493 tbr.len = SBYTES (specified_data);
7494 tbr.index = 0;
7495
7496
7497 if (tbr.len < sizeof sig
7498 || png_sig_cmp (tbr.bytes, 0, sizeof sig))
7499 {
7500 image_error ("Not a PNG image: `%s'", img->spec);
7501 return 0;
7502 }
7503
7504
7505 tbr.bytes += sizeof (sig);
7506 }
7507
7508
7509 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING,
7510 NULL, my_png_error,
7511 my_png_warning);
7512 if (png_ptr)
7513 {
7514 info_ptr = png_create_info_struct (png_ptr);
7515 end_info = png_create_info_struct (png_ptr);
7516 }
7517
7518 c->png_ptr = png_ptr;
7519 c->info_ptr = info_ptr;
7520 c->end_info = end_info;
7521 c->fp = fp;
7522 c->pixels = pixels;
7523 c->rows = rows;
7524
7525 if (! (info_ptr && end_info))
7526 {
7527 png_destroy_read_struct (&c->png_ptr, &c->info_ptr, &c->end_info);
7528 png_ptr = 0;
7529 }
7530 if (! png_ptr)
7531 {
7532 if (fp) fclose (fp);
7533 return 0;
7534 }
7535
7536
7537
7538 if (FAST_SETJMP (PNG_JMPBUF (png_ptr)))
7539 {
7540 error:
7541 if (c->png_ptr)
7542 png_destroy_read_struct (&c->png_ptr, &c->info_ptr, &c->end_info);
7543 xfree (c->pixels);
7544 xfree (c->rows);
7545 if (c->fp)
7546 fclose (c->fp);
7547 return 0;
7548 }
7549
7550
7551 if (!NILP (specified_data))
7552 png_set_read_fn (png_ptr, &tbr, png_read_from_memory);
7553 else
7554 png_set_read_fn (png_ptr, fp, png_read_from_file);
7555
7556 png_set_sig_bytes (png_ptr, sizeof sig);
7557 png_read_info (png_ptr, info_ptr);
7558 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
7559 &interlace_type, NULL, NULL);
7560
7561 if (! (width <= INT_MAX && height <= INT_MAX
7562 && check_image_size (f, width, height)))
7563 {
7564 image_size_error ();
7565 goto error;
7566 }
7567
7568
7569
7570 if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, 0))
7571 goto error;
7572
7573
7574
7575 transparent_p = false;
7576 # ifdef PNG_tRNS_SUPPORTED
7577 png_bytep trans_alpha;
7578 int num_trans;
7579 if (png_get_tRNS (png_ptr, info_ptr, &trans_alpha, &num_trans, NULL))
7580 {
7581 transparent_p = true;
7582 if (trans_alpha)
7583 for (int i = 0; i < num_trans; i++)
7584 if (0 < trans_alpha[i] && trans_alpha[i] < 255)
7585 {
7586 transparent_p = false;
7587 break;
7588 }
7589 }
7590 # endif
7591
7592
7593
7594
7595
7596
7597 if (bit_depth == 16)
7598 png_set_strip_16 (png_ptr);
7599
7600
7601
7602 png_set_expand (png_ptr);
7603
7604
7605 if (color_type == PNG_COLOR_TYPE_GRAY
7606 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
7607 png_set_gray_to_rgb (png_ptr);
7608
7609
7610
7611
7612 if (!transparent_p)
7613 {
7614
7615 Lisp_Object specified_bg
7616 = image_spec_value (img->spec, QCbackground, NULL);
7617 Emacs_Color color;
7618
7619
7620
7621
7622 if (STRINGP (specified_bg)
7623 ? FRAME_TERMINAL (f)->defined_color_hook (f,
7624 SSDATA (specified_bg),
7625 &color,
7626 false,
7627 false)
7628 : (FRAME_TERMINAL (f)->query_frame_background_color (f, &color),
7629 true))
7630
7631 {
7632 int shift = bit_depth == 16 ? 0 : 8;
7633 png_color_16 bg = { 0 };
7634 bg.red = color.red >> shift;
7635 bg.green = color.green >> shift;
7636 bg.blue = color.blue >> shift;
7637
7638 png_set_background (png_ptr, &bg,
7639 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
7640 }
7641 }
7642
7643 png_set_interlace_handling (png_ptr);
7644 png_read_update_info (png_ptr, info_ptr);
7645
7646
7647
7648
7649
7650
7651 channels = png_get_channels (png_ptr, info_ptr);
7652 eassert (channels == 3 || channels == 4);
7653
7654
7655 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
7656
7657
7658 if (INT_MULTIPLY_WRAPV (row_bytes, sizeof *pixels, &nbytes)
7659 || INT_MULTIPLY_WRAPV (nbytes, height, &nbytes))
7660 memory_full (SIZE_MAX);
7661 c->pixels = pixels = xmalloc (nbytes);
7662 c->rows = rows = xmalloc (height * sizeof *rows);
7663 for (i = 0; i < height; ++i)
7664 rows[i] = pixels + i * row_bytes;
7665
7666
7667 png_read_image (png_ptr, rows);
7668 png_read_end (png_ptr, info_ptr);
7669 if (fp)
7670 {
7671 fclose (fp);
7672 c->fp = NULL;
7673 }
7674
7675
7676
7677 if (channels == 4
7678 && transparent_p
7679 && !image_create_x_image_and_pixmap (f, img, width, height, 1,
7680 &mask_img, 1))
7681 {
7682 image_destroy_x_image (ximg);
7683 image_clear_image_1 (f, img, CLEAR_IMAGE_PIXMAP);
7684 goto error;
7685 }
7686
7687
7688 init_color_table ();
7689
7690 for (y = 0; y < height; ++y)
7691 {
7692 png_byte *p = rows[y];
7693
7694 for (x = 0; x < width; ++x)
7695 {
7696 int r, g, b;
7697
7698 r = *p++ << 8;
7699 g = *p++ << 8;
7700 b = *p++ << 8;
7701 PUT_PIXEL (ximg, x, y, lookup_rgb_color (f, r, g, b));
7702
7703
7704
7705
7706
7707
7708
7709
7710
7711
7712
7713
7714
7715
7716
7717
7718 if (channels == 4)
7719 {
7720 if (mask_img)
7721 PUT_PIXEL (mask_img, x, y, *p > 0 ? PIX_MASK_DRAW : PIX_MASK_RETAIN);
7722 ++p;
7723 }
7724 }
7725 }
7726
7727 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
7728
7729
7730 {
7731 png_color_16 *bg;
7732 if (png_get_bKGD (png_ptr, info_ptr, &bg))
7733 {
7734 #ifndef USE_CAIRO
7735 img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue);
7736 #else
7737 char color_name[30];
7738 sprintf (color_name, "#%04x%04x%04x", bg->red, bg->green, bg->blue);
7739 img->background
7740 = image_alloc_image_color (f, img, build_string (color_name), 0);
7741 #endif
7742 img->background_valid = 1;
7743 }
7744 }
7745
7746 # ifdef COLOR_TABLE_SUPPORT
7747
7748 img->colors = colors_in_color_table (&img->ncolors);
7749 free_color_table ();
7750 # endif
7751
7752
7753 png_destroy_read_struct (&c->png_ptr, &c->info_ptr, &c->end_info);
7754 xfree (rows);
7755 xfree (pixels);
7756
7757 img->width = width;
7758 img->height = height;
7759
7760
7761
7762 IMAGE_BACKGROUND (img, f, (Emacs_Pix_Context)ximg);
7763
7764
7765 image_put_x_image (f, img, ximg, 0);
7766
7767
7768 if (mask_img)
7769 {
7770
7771
7772 image_background_transparent (img, f, (Emacs_Pix_Context)mask_img);
7773
7774 image_put_x_image (f, img, mask_img, 1);
7775 }
7776
7777 return 1;
7778 }
7779
7780 static bool
7781 png_load (struct frame *f, struct image *img)
7782 {
7783 struct png_load_context c;
7784 return png_load_body (f, img, &c);
7785 }
7786
7787 #endif
7788
7789
7790
7791
7792
7793
7794
7795 #if defined (HAVE_JPEG)
7796
7797
7798
7799 enum jpeg_keyword_index
7800 {
7801 JPEG_TYPE,
7802 JPEG_DATA,
7803 JPEG_FILE,
7804 JPEG_ASCENT,
7805 JPEG_MARGIN,
7806 JPEG_RELIEF,
7807 JPEG_ALGORITHM,
7808 JPEG_HEURISTIC_MASK,
7809 JPEG_MASK,
7810 JPEG_BACKGROUND,
7811 JPEG_LAST
7812 };
7813
7814
7815
7816
7817 static const struct image_keyword jpeg_format[JPEG_LAST] =
7818 {
7819 {":type", IMAGE_SYMBOL_VALUE, 1},
7820 {":data", IMAGE_STRING_VALUE, 0},
7821 {":file", IMAGE_STRING_VALUE, 0},
7822 {":ascent", IMAGE_ASCENT_VALUE, 0},
7823 {":margin", IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR, 0},
7824 {":relief", IMAGE_INTEGER_VALUE, 0},
7825 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7826 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7827 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7828 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
7829 };
7830
7831
7832
7833 static bool
7834 jpeg_image_p (Lisp_Object object)
7835 {
7836 struct image_keyword fmt[JPEG_LAST];
7837
7838 memcpy (fmt, jpeg_format, sizeof fmt);
7839
7840 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg))
7841 return 0;
7842
7843
7844 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
7845 }
7846
7847 #endif
7848
7849 #ifdef HAVE_JPEG
7850
7851
7852
7853 # ifdef HAVE_STDLIB_H
7854 # undef HAVE_STDLIB_H
7855 # endif
7856
7857 # if defined (HAVE_NTGUI) && !defined (__WIN32__)
7858
7859
7860 # define __WIN32__ 1
7861 # endif
7862
7863
7864
7865
7866
7867
7868
7869
7870
7871
7872
7873
7874
7875
7876
7877 # if defined CYGWIN && defined HAVE_NTGUI
7878 # define boolean jpeg_boolean
7879 # endif
7880 # include <jpeglib.h>
7881 # include <jerror.h>
7882
7883 # ifdef WINDOWSNT
7884
7885
7886 DEF_DLL_FN (void, jpeg_CreateDecompress, (j_decompress_ptr, int, size_t));
7887 DEF_DLL_FN (boolean, jpeg_start_decompress, (j_decompress_ptr));
7888 DEF_DLL_FN (boolean, jpeg_finish_decompress, (j_decompress_ptr));
7889 DEF_DLL_FN (void, jpeg_destroy_decompress, (j_decompress_ptr));
7890 DEF_DLL_FN (int, jpeg_read_header, (j_decompress_ptr, boolean));
7891 DEF_DLL_FN (JDIMENSION, jpeg_read_scanlines,
7892 (j_decompress_ptr, JSAMPARRAY, JDIMENSION));
7893 DEF_DLL_FN (struct jpeg_error_mgr *, jpeg_std_error,
7894 (struct jpeg_error_mgr *));
7895 DEF_DLL_FN (boolean, jpeg_resync_to_restart, (j_decompress_ptr, int));
7896
7897 static bool
7898 init_jpeg_functions (void)
7899 {
7900 HMODULE library;
7901
7902 if (!(library = w32_delayed_load (Qjpeg)))
7903 return 0;
7904
7905 LOAD_DLL_FN (library, jpeg_finish_decompress);
7906 LOAD_DLL_FN (library, jpeg_read_scanlines);
7907 LOAD_DLL_FN (library, jpeg_start_decompress);
7908 LOAD_DLL_FN (library, jpeg_read_header);
7909 LOAD_DLL_FN (library, jpeg_CreateDecompress);
7910 LOAD_DLL_FN (library, jpeg_destroy_decompress);
7911 LOAD_DLL_FN (library, jpeg_std_error);
7912 LOAD_DLL_FN (library, jpeg_resync_to_restart);
7913 return 1;
7914 }
7915
7916 # undef jpeg_CreateDecompress
7917 # undef jpeg_destroy_decompress
7918 # undef jpeg_finish_decompress
7919 # undef jpeg_read_header
7920 # undef jpeg_read_scanlines
7921 # undef jpeg_resync_to_restart
7922 # undef jpeg_start_decompress
7923 # undef jpeg_std_error
7924
7925 # define jpeg_CreateDecompress fn_jpeg_CreateDecompress
7926 # define jpeg_destroy_decompress fn_jpeg_destroy_decompress
7927 # define jpeg_finish_decompress fn_jpeg_finish_decompress
7928 # define jpeg_read_header fn_jpeg_read_header
7929 # define jpeg_read_scanlines fn_jpeg_read_scanlines
7930 # define jpeg_resync_to_restart fn_jpeg_resync_to_restart
7931 # define jpeg_start_decompress fn_jpeg_start_decompress
7932 # define jpeg_std_error fn_jpeg_std_error
7933
7934
7935
7936 static boolean
7937 jpeg_resync_to_restart_wrapper (j_decompress_ptr cinfo, int desired)
7938 {
7939 return jpeg_resync_to_restart (cinfo, desired);
7940 }
7941 # undef jpeg_resync_to_restart
7942 # define jpeg_resync_to_restart jpeg_resync_to_restart_wrapper
7943
7944 # endif
7945
7946 struct my_jpeg_error_mgr
7947 {
7948 struct jpeg_error_mgr pub;
7949 sys_jmp_buf setjmp_buffer;
7950
7951
7952
7953 struct jpeg_decompress_struct cinfo;
7954 enum
7955 {
7956 MY_JPEG_ERROR_EXIT,
7957 MY_JPEG_INVALID_IMAGE_SIZE,
7958 MY_JPEG_CANNOT_CREATE_X
7959 } failure_code;
7960 };
7961
7962
7963 static AVOID
7964 my_error_exit (j_common_ptr cinfo)
7965 {
7966 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
7967 mgr->failure_code = MY_JPEG_ERROR_EXIT;
7968 sys_longjmp (mgr->setjmp_buffer, 1);
7969 }
7970
7971
7972
7973
7974
7975
7976 static void
7977 our_common_init_source (j_decompress_ptr cinfo)
7978 {
7979 }
7980
7981
7982
7983
7984
7985 static void
7986 our_common_term_source (j_decompress_ptr cinfo)
7987 {
7988 }
7989
7990
7991
7992
7993
7994
7995 static JOCTET our_memory_buffer[2];
7996
7997 static boolean
7998 our_memory_fill_input_buffer (j_decompress_ptr cinfo)
7999 {
8000
8001 struct jpeg_source_mgr *src = cinfo->src;
8002
8003 our_memory_buffer[0] = (JOCTET) 0xFF;
8004 our_memory_buffer[1] = (JOCTET) JPEG_EOI;
8005
8006 src->next_input_byte = our_memory_buffer;
8007 src->bytes_in_buffer = 2;
8008 return 1;
8009 }
8010
8011
8012
8013
8014
8015 static void
8016 our_memory_skip_input_data (j_decompress_ptr cinfo, long int num_bytes)
8017 {
8018 struct jpeg_source_mgr *src = cinfo->src;
8019
8020 if (src)
8021 {
8022 if (num_bytes > src->bytes_in_buffer)
8023 ERREXIT (cinfo, JERR_INPUT_EOF);
8024
8025 src->bytes_in_buffer -= num_bytes;
8026 src->next_input_byte += num_bytes;
8027 }
8028 }
8029
8030
8031
8032
8033
8034
8035 static void
8036 jpeg_memory_src (j_decompress_ptr cinfo, JOCTET *data, ptrdiff_t len)
8037 {
8038 struct jpeg_source_mgr *src = cinfo->src;
8039
8040 if (! src)
8041 {
8042
8043 src = cinfo->mem->alloc_small ((j_common_ptr) cinfo,
8044 JPOOL_PERMANENT, sizeof *src);
8045 cinfo->src = src;
8046 src->next_input_byte = data;
8047 }
8048
8049 src->init_source = our_common_init_source;
8050 src->fill_input_buffer = our_memory_fill_input_buffer;
8051 src->skip_input_data = our_memory_skip_input_data;
8052 src->resync_to_restart = jpeg_resync_to_restart;
8053 src->term_source = our_common_term_source;
8054 src->bytes_in_buffer = len;
8055 src->next_input_byte = data;
8056 }
8057
8058
8059 struct jpeg_stdio_mgr
8060 {
8061 struct jpeg_source_mgr mgr;
8062 boolean finished;
8063 FILE *file;
8064 JOCTET *buffer;
8065 };
8066
8067
8068
8069
8070 #define JPEG_STDIO_BUFFER_SIZE 8192
8071
8072
8073
8074
8075
8076 static boolean
8077 our_stdio_fill_input_buffer (j_decompress_ptr cinfo)
8078 {
8079 struct jpeg_stdio_mgr *src;
8080
8081 src = (struct jpeg_stdio_mgr *) cinfo->src;
8082 if (!src->finished)
8083 {
8084 ptrdiff_t bytes;
8085
8086 bytes = fread (src->buffer, 1, JPEG_STDIO_BUFFER_SIZE, src->file);
8087 if (bytes > 0)
8088 src->mgr.bytes_in_buffer = bytes;
8089 else
8090 {
8091 WARNMS (cinfo, JWRN_JPEG_EOF);
8092 src->finished = 1;
8093 src->buffer[0] = (JOCTET) 0xFF;
8094 src->buffer[1] = (JOCTET) JPEG_EOI;
8095 src->mgr.bytes_in_buffer = 2;
8096 }
8097 src->mgr.next_input_byte = src->buffer;
8098 }
8099
8100 return 1;
8101 }
8102
8103
8104
8105
8106
8107 static void
8108 our_stdio_skip_input_data (j_decompress_ptr cinfo, long int num_bytes)
8109 {
8110 struct jpeg_stdio_mgr *src;
8111 src = (struct jpeg_stdio_mgr *) cinfo->src;
8112
8113 while (num_bytes > 0 && !src->finished)
8114 {
8115 if (num_bytes <= src->mgr.bytes_in_buffer)
8116 {
8117 src->mgr.bytes_in_buffer -= num_bytes;
8118 src->mgr.next_input_byte += num_bytes;
8119 break;
8120 }
8121 else
8122 {
8123 num_bytes -= src->mgr.bytes_in_buffer;
8124 src->mgr.bytes_in_buffer = 0;
8125 src->mgr.next_input_byte = NULL;
8126
8127 our_stdio_fill_input_buffer (cinfo);
8128 }
8129 }
8130 }
8131
8132
8133
8134
8135
8136
8137 static void
8138 jpeg_file_src (j_decompress_ptr cinfo, FILE *fp)
8139 {
8140 struct jpeg_stdio_mgr *src = (struct jpeg_stdio_mgr *) cinfo->src;
8141
8142 if (! src)
8143 {
8144
8145 src = cinfo->mem->alloc_small ((j_common_ptr) cinfo,
8146 JPOOL_PERMANENT, sizeof *src);
8147 cinfo->src = (struct jpeg_source_mgr *) src;
8148 src->buffer = cinfo->mem->alloc_small ((j_common_ptr) cinfo,
8149 JPOOL_PERMANENT,
8150 JPEG_STDIO_BUFFER_SIZE);
8151 }
8152
8153 src->file = fp;
8154 src->finished = 0;
8155 src->mgr.init_source = our_common_init_source;
8156 src->mgr.fill_input_buffer = our_stdio_fill_input_buffer;
8157 src->mgr.skip_input_data = our_stdio_skip_input_data;
8158 src->mgr.resync_to_restart = jpeg_resync_to_restart;
8159 src->mgr.term_source = our_common_term_source;
8160 src->mgr.bytes_in_buffer = 0;
8161 src->mgr.next_input_byte = NULL;
8162 }
8163
8164
8165
8166
8167 static bool
8168 jpeg_load_body (struct frame *f, struct image *img,
8169 struct my_jpeg_error_mgr *mgr)
8170 {
8171 Lisp_Object specified_file, specified_data;
8172 FILE *volatile fp = NULL;
8173 JSAMPARRAY buffer;
8174 int row_stride, x, y;
8175 int width, height;
8176 int i, ir, ig, ib;
8177 unsigned long *colors;
8178 Emacs_Pix_Container ximg = NULL;
8179
8180
8181 specified_file = image_spec_value (img->spec, QCfile, NULL);
8182 specified_data = image_spec_value (img->spec, QCdata, NULL);
8183
8184 if (NILP (specified_data))
8185 {
8186 int fd;
8187 Lisp_Object file = image_find_image_fd (specified_file, &fd);
8188 if (!STRINGP (file))
8189 {
8190 image_error ("Cannot find image file `%s'", specified_file);
8191 return 0;
8192 }
8193
8194 fp = fdopen (fd, "rb");
8195 if (fp == NULL)
8196 {
8197 image_error ("Cannot open `%s'", file);
8198 return 0;
8199 }
8200 }
8201 else if (!STRINGP (specified_data))
8202 {
8203 image_error ("Invalid image data `%s'", specified_data);
8204 return 0;
8205 }
8206
8207
8208
8209 mgr->cinfo.err = jpeg_std_error (&mgr->pub);
8210 mgr->pub.error_exit = my_error_exit;
8211 if (sys_setjmp (mgr->setjmp_buffer))
8212 {
8213 switch (mgr->failure_code)
8214 {
8215 case MY_JPEG_ERROR_EXIT:
8216 {
8217 char buf[JMSG_LENGTH_MAX];
8218 mgr->cinfo.err->format_message ((j_common_ptr) &mgr->cinfo, buf);
8219 image_error ("Error reading JPEG image `%s': %s",
8220 img->spec, build_string (buf));
8221 break;
8222 }
8223
8224 case MY_JPEG_INVALID_IMAGE_SIZE:
8225 image_size_error ();
8226 break;
8227
8228 case MY_JPEG_CANNOT_CREATE_X:
8229 break;
8230 }
8231
8232
8233 if (fp)
8234 fclose (fp);
8235 jpeg_destroy_decompress (&mgr->cinfo);
8236
8237
8238 image_destroy_x_image (ximg);
8239
8240 image_clear_image (f, img);
8241 return 0;
8242 }
8243
8244
8245
8246 jpeg_CreateDecompress (&mgr->cinfo, JPEG_LIB_VERSION, sizeof *&mgr->cinfo);
8247
8248 if (NILP (specified_data))
8249 jpeg_file_src (&mgr->cinfo, fp);
8250 else
8251 jpeg_memory_src (&mgr->cinfo, SDATA (specified_data),
8252 SBYTES (specified_data));
8253
8254 jpeg_read_header (&mgr->cinfo, 1);
8255
8256
8257
8258 mgr->cinfo.quantize_colors = 1;
8259 jpeg_start_decompress (&mgr->cinfo);
8260 width = img->width = mgr->cinfo.output_width;
8261 height = img->height = mgr->cinfo.output_height;
8262
8263 if (!check_image_size (f, width, height))
8264 {
8265 mgr->failure_code = MY_JPEG_INVALID_IMAGE_SIZE;
8266 sys_longjmp (mgr->setjmp_buffer, 1);
8267 }
8268
8269
8270 if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, 0))
8271 {
8272 mgr->failure_code = MY_JPEG_CANNOT_CREATE_X;
8273 sys_longjmp (mgr->setjmp_buffer, 1);
8274 }
8275
8276
8277
8278
8279
8280
8281 USE_SAFE_ALLOCA;
8282 {
8283 if (mgr->cinfo.out_color_components > 2)
8284 ir = 0, ig = 1, ib = 2;
8285 else if (mgr->cinfo.out_color_components > 1)
8286 ir = 0, ig = 1, ib = 0;
8287 else
8288 ir = 0, ig = 0, ib = 0;
8289
8290
8291
8292
8293
8294 init_color_table ();
8295 SAFE_NALLOCA (colors, 1, mgr->cinfo.actual_number_of_colors);
8296
8297 for (i = 0; i < mgr->cinfo.actual_number_of_colors; ++i)
8298 {
8299
8300
8301 int r = mgr->cinfo.colormap[ir][i] << 8;
8302 int g = mgr->cinfo.colormap[ig][i] << 8;
8303 int b = mgr->cinfo.colormap[ib][i] << 8;
8304 colors[i] = lookup_rgb_color (f, r, g, b);
8305 }
8306
8307 #ifdef COLOR_TABLE_SUPPORT
8308
8309 img->colors = colors_in_color_table (&img->ncolors);
8310 free_color_table ();
8311 #endif
8312 }
8313
8314
8315 row_stride = width * mgr->cinfo.output_components;
8316 buffer = mgr->cinfo.mem->alloc_sarray ((j_common_ptr) &mgr->cinfo,
8317 JPOOL_IMAGE, row_stride, 1);
8318 for (y = 0; y < height; ++y)
8319 {
8320 jpeg_read_scanlines (&mgr->cinfo, buffer, 1);
8321 for (x = 0; x < mgr->cinfo.output_width; ++x)
8322 PUT_PIXEL (ximg, x, y, colors[buffer[0][x]]);
8323 }
8324
8325
8326 jpeg_finish_decompress (&mgr->cinfo);
8327 jpeg_destroy_decompress (&mgr->cinfo);
8328 if (fp)
8329 fclose (fp);
8330
8331
8332 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
8333
8334 IMAGE_BACKGROUND (img, f, (Emacs_Pix_Context)ximg);
8335
8336
8337 image_put_x_image (f, img, ximg, 0);
8338 SAFE_FREE ();
8339 return 1;
8340 }
8341
8342 static bool
8343 jpeg_load (struct frame *f, struct image *img)
8344 {
8345 struct my_jpeg_error_mgr mgr;
8346 return jpeg_load_body (f, img, &mgr);
8347 }
8348
8349 #endif
8350
8351
8352
8353
8354
8355
8356
8357 #if defined (HAVE_TIFF)
8358
8359
8360
8361 enum tiff_keyword_index
8362 {
8363 TIFF_TYPE,
8364 TIFF_DATA,
8365 TIFF_FILE,
8366 TIFF_ASCENT,
8367 TIFF_MARGIN,
8368 TIFF_RELIEF,
8369 TIFF_ALGORITHM,
8370 TIFF_HEURISTIC_MASK,
8371 TIFF_MASK,
8372 TIFF_BACKGROUND,
8373 TIFF_INDEX,
8374 TIFF_LAST
8375 };
8376
8377
8378
8379
8380 static const struct image_keyword tiff_format[TIFF_LAST] =
8381 {
8382 {":type", IMAGE_SYMBOL_VALUE, 1},
8383 {":data", IMAGE_STRING_VALUE, 0},
8384 {":file", IMAGE_STRING_VALUE, 0},
8385 {":ascent", IMAGE_ASCENT_VALUE, 0},
8386 {":margin", IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR, 0},
8387 {":relief", IMAGE_INTEGER_VALUE, 0},
8388 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8389 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8390 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8391 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
8392 {":index", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}
8393 };
8394
8395
8396
8397 static bool
8398 tiff_image_p (Lisp_Object object)
8399 {
8400 struct image_keyword fmt[TIFF_LAST];
8401 memcpy (fmt, tiff_format, sizeof fmt);
8402
8403 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff))
8404 return 0;
8405
8406
8407 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
8408 }
8409
8410 #endif
8411
8412 #ifdef HAVE_TIFF
8413
8414 # include <tiffio.h>
8415
8416
8417 #if TIFFLIB_VERSION >= 20210416
8418 # define UINT32 uint32_t
8419 #else
8420 # define UINT32 uint32
8421 #endif
8422
8423 # ifdef WINDOWSNT
8424
8425
8426 DEF_DLL_FN (TIFFErrorHandler, TIFFSetErrorHandler, (TIFFErrorHandler));
8427 DEF_DLL_FN (TIFFErrorHandler, TIFFSetWarningHandler, (TIFFErrorHandler));
8428 DEF_DLL_FN (TIFF *, TIFFOpen, (const char *, const char *));
8429 DEF_DLL_FN (TIFF *, TIFFClientOpen,
8430 (const char *, const char *, thandle_t, TIFFReadWriteProc,
8431 TIFFReadWriteProc, TIFFSeekProc, TIFFCloseProc, TIFFSizeProc,
8432 TIFFMapFileProc, TIFFUnmapFileProc));
8433 DEF_DLL_FN (int, TIFFGetField, (TIFF *, ttag_t, ...));
8434 DEF_DLL_FN (int, TIFFReadRGBAImage, (TIFF *, UINT32, UINT32, UINT32 *, int));
8435 DEF_DLL_FN (void, TIFFClose, (TIFF *));
8436 DEF_DLL_FN (int, TIFFSetDirectory, (TIFF *, tdir_t));
8437
8438 static bool
8439 init_tiff_functions (void)
8440 {
8441 HMODULE library;
8442
8443 if (!(library = w32_delayed_load (Qtiff)))
8444 return 0;
8445
8446 LOAD_DLL_FN (library, TIFFSetErrorHandler);
8447 LOAD_DLL_FN (library, TIFFSetWarningHandler);
8448 LOAD_DLL_FN (library, TIFFOpen);
8449 LOAD_DLL_FN (library, TIFFClientOpen);
8450 LOAD_DLL_FN (library, TIFFGetField);
8451 LOAD_DLL_FN (library, TIFFReadRGBAImage);
8452 LOAD_DLL_FN (library, TIFFClose);
8453 LOAD_DLL_FN (library, TIFFSetDirectory);
8454 return 1;
8455 }
8456
8457 # undef TIFFClientOpen
8458 # undef TIFFClose
8459 # undef TIFFGetField
8460 # undef TIFFOpen
8461 # undef TIFFReadRGBAImage
8462 # undef TIFFSetDirectory
8463 # undef TIFFSetErrorHandler
8464 # undef TIFFSetWarningHandler
8465
8466 # define TIFFClientOpen fn_TIFFClientOpen
8467 # define TIFFClose fn_TIFFClose
8468 # define TIFFGetField fn_TIFFGetField
8469 # define TIFFOpen fn_TIFFOpen
8470 # define TIFFReadRGBAImage fn_TIFFReadRGBAImage
8471 # define TIFFSetDirectory fn_TIFFSetDirectory
8472 # define TIFFSetErrorHandler fn_TIFFSetErrorHandler
8473 # define TIFFSetWarningHandler fn_TIFFSetWarningHandler
8474
8475 # endif
8476
8477
8478
8479
8480
8481
8482
8483
8484
8485
8486
8487 typedef struct
8488 {
8489 unsigned char *bytes;
8490 ptrdiff_t len;
8491 ptrdiff_t index;
8492 }
8493 tiff_memory_source;
8494
8495 static tsize_t
8496 tiff_read_from_memory (thandle_t data, tdata_t buf, tsize_t size)
8497 {
8498 tiff_memory_source *src = (tiff_memory_source *) data;
8499
8500 size = min (size, src->len - src->index);
8501 memcpy (buf, src->bytes + src->index, size);
8502 src->index += size;
8503 return size;
8504 }
8505
8506 static tsize_t
8507 tiff_write_from_memory (thandle_t data, tdata_t buf, tsize_t size)
8508 {
8509 return -1;
8510 }
8511
8512 static toff_t
8513 tiff_seek_in_memory (thandle_t data, toff_t off, int whence)
8514 {
8515 tiff_memory_source *src = (tiff_memory_source *) data;
8516 ptrdiff_t idx;
8517
8518 switch (whence)
8519 {
8520 case SEEK_SET:
8521 idx = off;
8522 break;
8523
8524 case SEEK_END:
8525 idx = src->len + off;
8526 break;
8527
8528 case SEEK_CUR:
8529 idx = src->index + off;
8530 break;
8531
8532 default:
8533 return -1;
8534 }
8535
8536 if (idx > src->len || idx < 0)
8537 return -1;
8538
8539 src->index = idx;
8540 return src->index;
8541 }
8542
8543 static int
8544 tiff_close_memory (thandle_t data)
8545 {
8546
8547 return 0;
8548 }
8549
8550 static int
8551 tiff_mmap_memory (thandle_t data, tdata_t *pbase, toff_t *psize)
8552 {
8553
8554 return 0;
8555 }
8556
8557 static void
8558 tiff_unmap_memory (thandle_t data, tdata_t base, toff_t size)
8559 {
8560
8561 }
8562
8563 static toff_t
8564 tiff_size_of_memory (thandle_t data)
8565 {
8566 return ((tiff_memory_source *) data)->len;
8567 }
8568
8569
8570
8571
8572
8573 # if defined (__MINGW32__) && __GNUC__ == 3
8574 # define MINGW_STATIC
8575 # else
8576 # define MINGW_STATIC static
8577 # endif
8578
8579 MINGW_STATIC void
8580 tiff_handler (const char *, const char *, const char *, va_list)
8581 ATTRIBUTE_FORMAT_PRINTF (3, 0);
8582 MINGW_STATIC void
8583 tiff_handler (const char *log_format, const char *title,
8584 const char *format, va_list ap)
8585 {
8586
8587
8588
8589
8590
8591 char buf[4000];
8592 int len = vsnprintf (buf, sizeof buf, format, ap);
8593 add_to_log (log_format, build_string (title),
8594 make_string (buf, max (0, min (len, sizeof buf - 1))));
8595 }
8596 # undef MINGW_STATIC
8597
8598 static void tiff_error_handler (const char *, const char *, va_list)
8599 ATTRIBUTE_FORMAT_PRINTF (2, 0);
8600 static void
8601 tiff_error_handler (const char *title, const char *format, va_list ap)
8602 {
8603 tiff_handler ("TIFF error: %s %s", title, format, ap);
8604 }
8605
8606
8607 static void tiff_warning_handler (const char *, const char *, va_list)
8608 ATTRIBUTE_FORMAT_PRINTF (2, 0);
8609 static void
8610 tiff_warning_handler (const char *title, const char *format, va_list ap)
8611 {
8612 tiff_handler ("TIFF warning: %s %s", title, format, ap);
8613 }
8614
8615
8616
8617
8618
8619 static bool
8620 tiff_load (struct frame *f, struct image *img)
8621 {
8622 Lisp_Object specified_file;
8623 Lisp_Object specified_data;
8624 TIFF *tiff;
8625 int width, height, x, y, count;
8626 UINT32 *buf;
8627 int rc;
8628 Emacs_Pix_Container ximg;
8629 tiff_memory_source memsrc;
8630 Lisp_Object image;
8631
8632 specified_file = image_spec_value (img->spec, QCfile, NULL);
8633 specified_data = image_spec_value (img->spec, QCdata, NULL);
8634
8635 TIFFSetErrorHandler ((TIFFErrorHandler) tiff_error_handler);
8636 TIFFSetWarningHandler ((TIFFErrorHandler) tiff_warning_handler);
8637
8638 if (NILP (specified_data))
8639 {
8640
8641 Lisp_Object file = image_find_image_file (specified_file);
8642 if (!STRINGP (file))
8643 {
8644 image_error ("Cannot find image file `%s'", specified_file);
8645 return 0;
8646 }
8647
8648 Lisp_Object encoded_file = ENCODE_FILE (file);
8649 # ifdef WINDOWSNT
8650 encoded_file = ansi_encode_filename (encoded_file);
8651 # endif
8652
8653
8654 tiff = TIFFOpen (SSDATA (encoded_file), "r");
8655 if (tiff == NULL)
8656 {
8657 image_error ("Cannot open `%s'", file);
8658 return 0;
8659 }
8660 }
8661 else
8662 {
8663 if (!STRINGP (specified_data))
8664 {
8665 image_error ("Invalid image data `%s'", specified_data);
8666 return 0;
8667 }
8668
8669
8670 memsrc.bytes = SDATA (specified_data);
8671 memsrc.len = SBYTES (specified_data);
8672 memsrc.index = 0;
8673
8674 tiff = TIFFClientOpen ("memory_source", "r", (thandle_t)&memsrc,
8675 tiff_read_from_memory,
8676 tiff_write_from_memory,
8677 tiff_seek_in_memory,
8678 tiff_close_memory,
8679 tiff_size_of_memory,
8680 tiff_mmap_memory,
8681 tiff_unmap_memory);
8682
8683 if (!tiff)
8684 {
8685 image_error ("Cannot open memory source for `%s'", img->spec);
8686 return 0;
8687 }
8688 }
8689
8690 image = image_spec_value (img->spec, QCindex, NULL);
8691 if (FIXNUMP (image))
8692 {
8693 EMACS_INT ino = XFIXNAT (image);
8694 if (! (TYPE_MINIMUM (tdir_t) <= ino && ino <= TYPE_MAXIMUM (tdir_t)
8695 && TIFFSetDirectory (tiff, ino)))
8696 {
8697 image_error ("Invalid image number `%s' in image `%s'",
8698 image, img->spec);
8699 TIFFClose (tiff);
8700 return 0;
8701 }
8702 }
8703
8704
8705
8706 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
8707 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
8708
8709 if (!check_image_size (f, width, height))
8710 {
8711 image_size_error ();
8712 TIFFClose (tiff);
8713 return 0;
8714 }
8715
8716
8717 if (! (height <= min (PTRDIFF_MAX, SIZE_MAX) / sizeof *buf / width
8718 && image_create_x_image_and_pixmap (f, img, width, height, 0,
8719 &ximg, 0)))
8720 {
8721 TIFFClose (tiff);
8722 return 0;
8723 }
8724
8725 buf = xmalloc (sizeof *buf * width * height);
8726
8727 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
8728
8729
8730 for (count = 1; TIFFSetDirectory (tiff, count); count++)
8731 continue;
8732
8733 if (count > 1)
8734 img->lisp_data = Fcons (Qcount,
8735 Fcons (make_fixnum (count),
8736 img->lisp_data));
8737
8738 TIFFClose (tiff);
8739 if (!rc)
8740 {
8741 image_error ("Error reading TIFF image `%s'", img->spec);
8742 xfree (buf);
8743 return 0;
8744 }
8745
8746
8747 init_color_table ();
8748
8749
8750 for (y = 0; y < height; ++y)
8751 {
8752 UINT32 *row = buf + y * width;
8753
8754 for (x = 0; x < width; ++x)
8755 {
8756 UINT32 abgr = row[x];
8757 int r = TIFFGetR (abgr) << 8;
8758 int g = TIFFGetG (abgr) << 8;
8759 int b = TIFFGetB (abgr) << 8;
8760 PUT_PIXEL (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
8761 }
8762 }
8763
8764 # ifdef COLOR_TABLE_SUPPORT
8765
8766 img->colors = colors_in_color_table (&img->ncolors);
8767 free_color_table ();
8768 # endif
8769
8770 img->width = width;
8771 img->height = height;
8772
8773
8774 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
8775
8776 IMAGE_BACKGROUND (img, f, (Emacs_Pix_Context)ximg);
8777
8778
8779 image_put_x_image (f, img, ximg, 0);
8780
8781 xfree (buf);
8782 return 1;
8783 }
8784
8785 #endif
8786
8787
8788
8789
8790
8791
8792
8793 #if defined (HAVE_GIF)
8794
8795
8796
8797 enum gif_keyword_index
8798 {
8799 GIF_TYPE,
8800 GIF_DATA,
8801 GIF_FILE,
8802 GIF_ASCENT,
8803 GIF_MARGIN,
8804 GIF_RELIEF,
8805 GIF_ALGORITHM,
8806 GIF_HEURISTIC_MASK,
8807 GIF_MASK,
8808 GIF_IMAGE,
8809 GIF_BACKGROUND,
8810 GIF_LAST
8811 };
8812
8813
8814
8815
8816 static const struct image_keyword gif_format[GIF_LAST] =
8817 {
8818 {":type", IMAGE_SYMBOL_VALUE, 1},
8819 {":data", IMAGE_STRING_VALUE, 0},
8820 {":file", IMAGE_STRING_VALUE, 0},
8821 {":ascent", IMAGE_ASCENT_VALUE, 0},
8822 {":margin", IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR, 0},
8823 {":relief", IMAGE_INTEGER_VALUE, 0},
8824 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8825 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8826 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8827 {":index", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8828 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
8829 };
8830
8831
8832
8833 static void
8834 gif_clear_image (struct frame *f, struct image *img)
8835 {
8836 img->lisp_data = Qnil;
8837 image_clear_image (f, img);
8838 }
8839
8840
8841
8842 static bool
8843 gif_image_p (Lisp_Object object)
8844 {
8845 struct image_keyword fmt[GIF_LAST];
8846 memcpy (fmt, gif_format, sizeof fmt);
8847
8848 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif))
8849 return 0;
8850
8851
8852 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
8853 }
8854
8855 #endif
8856
8857 #ifdef HAVE_GIF
8858
8859 # ifdef HAVE_NTGUI
8860
8861
8862
8863 # ifdef DrawText
8864 # undef DrawText
8865 # endif
8866
8867 # define DrawText gif_DrawText
8868 # include <gif_lib.h>
8869
8870
8871 # ifdef DrawText
8872 # undef DrawText
8873 # endif
8874
8875 # else
8876
8877 # include <gif_lib.h>
8878
8879 # endif
8880
8881
8882 # ifndef GIFLIB_MAJOR
8883 # define GIFLIB_MAJOR 4
8884 # endif
8885 # ifndef GIFLIB_MINOR
8886 # define GIFLIB_MINOR 0
8887 # endif
8888 # ifndef GIFLIB_RELEASE
8889 # define GIFLIB_RELEASE 0
8890 # endif
8891
8892 # if GIFLIB_MAJOR < 5
8893 # define DISPOSAL_UNSPECIFIED 0
8894 # define DISPOSE_DO_NOT 1
8895 # define DISPOSE_BACKGROUND 2
8896 # define DISPOSE_PREVIOUS 3
8897 # define NO_TRANSPARENT_COLOR -1
8898 # endif
8899
8900
8901
8902
8903
8904 # define HAVE_GIFERRORSTRING (5 < GIFLIB_MAJOR + (1 <= GIFLIB_MINOR))
8905
8906 # ifdef WINDOWSNT
8907
8908
8909 # if GIFLIB_MAJOR + (GIFLIB_MINOR >= 1) > 5
8910 DEF_DLL_FN (int, DGifCloseFile, (GifFileType *, int *));
8911 # else
8912 DEF_DLL_FN (int, DGifCloseFile, (GifFileType *));
8913 # endif
8914 DEF_DLL_FN (int, DGifSlurp, (GifFileType *));
8915 # if GIFLIB_MAJOR < 5
8916 DEF_DLL_FN (GifFileType *, DGifOpen, (void *, InputFunc));
8917 DEF_DLL_FN (GifFileType *, DGifOpenFileName, (const char *));
8918 # else
8919 DEF_DLL_FN (GifFileType *, DGifOpen, (void *, InputFunc, int *));
8920 DEF_DLL_FN (GifFileType *, DGifOpenFileName, (const char *, int *));
8921 DEF_DLL_FN (int, DGifSavedExtensionToGCB,
8922 (GifFileType *, int, GraphicsControlBlock *));
8923 # endif
8924 # if HAVE_GIFERRORSTRING
8925 DEF_DLL_FN (char const *, GifErrorString, (int));
8926 # endif
8927
8928 static bool
8929 init_gif_functions (void)
8930 {
8931 HMODULE library;
8932
8933 if (!(library = w32_delayed_load (Qgif)))
8934 return 0;
8935
8936 LOAD_DLL_FN (library, DGifCloseFile);
8937 LOAD_DLL_FN (library, DGifSlurp);
8938 LOAD_DLL_FN (library, DGifOpen);
8939 LOAD_DLL_FN (library, DGifOpenFileName);
8940 # if GIFLIB_MAJOR >= 5
8941 LOAD_DLL_FN (library, DGifSavedExtensionToGCB);
8942 # endif
8943 # if HAVE_GIFERRORSTRING
8944 LOAD_DLL_FN (library, GifErrorString);
8945 # endif
8946 return 1;
8947 }
8948
8949 # undef DGifCloseFile
8950 # undef DGifOpen
8951 # undef DGifOpenFileName
8952 # undef DGifSlurp
8953 # if GIFLIB_MAJOR >= 5
8954 # undef DGifSavedExtensionToGCB
8955 # endif
8956 # undef GifErrorString
8957
8958 # define DGifCloseFile fn_DGifCloseFile
8959 # define DGifOpen fn_DGifOpen
8960 # define DGifOpenFileName fn_DGifOpenFileName
8961 # define DGifSlurp fn_DGifSlurp
8962 # if GIFLIB_MAJOR >= 5
8963 # define DGifSavedExtensionToGCB fn_DGifSavedExtensionToGCB
8964 # endif
8965 # define GifErrorString fn_GifErrorString
8966
8967 # endif
8968
8969
8970
8971
8972 typedef struct
8973 {
8974 unsigned char *bytes;
8975 ptrdiff_t len;
8976 ptrdiff_t index;
8977 }
8978 gif_memory_source;
8979
8980
8981
8982
8983 static gif_memory_source *current_gif_memory_src;
8984
8985 static int
8986 gif_read_from_memory (GifFileType *file, GifByteType *buf, int len)
8987 {
8988 gif_memory_source *src = current_gif_memory_src;
8989
8990 if (len > src->len - src->index)
8991 return -1;
8992
8993 memcpy (buf, src->bytes + src->index, len);
8994 src->index += len;
8995 return len;
8996 }
8997
8998 static int
8999 gif_close (GifFileType *gif, int *err)
9000 {
9001 int retval;
9002
9003 #if GIFLIB_MAJOR + (GIFLIB_MINOR >= 1) > 5
9004 retval = DGifCloseFile (gif, err);
9005 #else
9006 retval = DGifCloseFile (gif);
9007 #if GIFLIB_MAJOR >= 5
9008 if (err)
9009 *err = gif->Error;
9010 #endif
9011 #endif
9012 return retval;
9013 }
9014
9015
9016
9017
9018 static const int interlace_start[] = {0, 4, 2, 1};
9019 static const int interlace_increment[] = {8, 8, 4, 2};
9020
9021 #define GIF_LOCAL_DESCRIPTOR_EXTENSION 249
9022
9023 static void
9024 gif_destroy (struct anim_cache* cache)
9025 {
9026 int gif_err;
9027 gif_close (cache->handle, &gif_err);
9028 }
9029
9030 static bool
9031 gif_load (struct frame *f, struct image *img)
9032 {
9033 int rc, width, height, x, y, i, j;
9034 ColorMapObject *gif_color_map;
9035 GifFileType *gif = NULL;
9036 gif_memory_source memsrc;
9037 Lisp_Object specified_bg = image_spec_value (img->spec, QCbackground, NULL);
9038 Lisp_Object specified_file = image_spec_value (img->spec, QCfile, NULL);
9039 Lisp_Object specified_data = image_spec_value (img->spec, QCdata, NULL);
9040 unsigned long *pixmap = NULL;
9041 EMACS_INT idx = -1;
9042 int gif_err;
9043 struct anim_cache* cache = NULL;
9044
9045 Lisp_Object image_number = image_spec_value (img->spec, QCindex, NULL);
9046 int byte_size = 0;
9047
9048 idx = FIXNUMP (image_number) ? XFIXNAT (image_number) : 0;
9049
9050 if (!NILP (image_number))
9051 {
9052
9053 cache = anim_get_animation_cache (XCDR (img->spec));
9054
9055 if (cache->handle)
9056 {
9057 gif = cache->handle;
9058 pixmap = cache->temp;
9059
9060 if (cache->index != idx - 1)
9061 cache->index = -1;
9062 }
9063 }
9064
9065
9066 if (! gif)
9067 {
9068 if (NILP (specified_data))
9069 {
9070 Lisp_Object file = image_find_image_file (specified_file);
9071 if (!STRINGP (file))
9072 {
9073 image_error ("Cannot find image file `%s'", specified_file);
9074 return false;
9075 }
9076
9077 Lisp_Object encoded_file = ENCODE_FILE (file);
9078 #ifdef WINDOWSNT
9079 encoded_file = ansi_encode_filename (encoded_file);
9080 #endif
9081
9082
9083 #if GIFLIB_MAJOR < 5
9084 gif = DGifOpenFileName (SSDATA (encoded_file));
9085 #else
9086 gif = DGifOpenFileName (SSDATA (encoded_file), &gif_err);
9087 #endif
9088 if (gif == NULL)
9089 {
9090 #if HAVE_GIFERRORSTRING
9091 const char *errstr = GifErrorString (gif_err);
9092 if (errstr)
9093 image_error ("Cannot open `%s': %s", file,
9094 build_string (errstr));
9095 else
9096 #endif
9097 image_error ("Cannot open `%s'", file);
9098 return false;
9099 }
9100
9101
9102
9103 struct stat st;
9104 FILE *fp = fopen (SSDATA (encoded_file), "rb");
9105 if (fstat (fileno (fp), &st) == 0)
9106 byte_size = st.st_size;
9107 fclose (fp);
9108 }
9109 else
9110 {
9111 if (!STRINGP (specified_data))
9112 {
9113 image_error ("Invalid image data `%s'", specified_data);
9114 return false;
9115 }
9116
9117
9118 current_gif_memory_src = &memsrc;
9119 memsrc.bytes = SDATA (specified_data);
9120 memsrc.len = SBYTES (specified_data);
9121 memsrc.index = 0;
9122 byte_size = memsrc.len;
9123
9124 #if GIFLIB_MAJOR < 5
9125 gif = DGifOpen (&memsrc, gif_read_from_memory);
9126 #else
9127 gif = DGifOpen (&memsrc, gif_read_from_memory, &gif_err);
9128 #endif
9129 if (!gif)
9130 {
9131 #if HAVE_GIFERRORSTRING
9132 const char *errstr = GifErrorString (gif_err);
9133 if (errstr)
9134 image_error ("Cannot open memory source `%s': %s",
9135 img->spec, build_string (errstr));
9136 else
9137 #endif
9138 image_error ("Cannot open memory source `%s'", img->spec);
9139 return false;
9140 }
9141 }
9142
9143
9144 if (!check_image_size (f, gif->SWidth, gif->SHeight))
9145 {
9146 image_size_error ();
9147 goto gif_error;
9148 }
9149
9150
9151 rc = DGifSlurp (gif);
9152 if (rc == GIF_ERROR || gif->ImageCount <= 0)
9153 {
9154 #if HAVE_GIFERRORSTRING
9155 const char *errstr = GifErrorString (gif->Error);
9156 if (errstr)
9157 if (NILP (specified_data))
9158 image_error ("Error reading `%s' (%s)", img->spec,
9159 build_string (errstr));
9160 else
9161 image_error ("Error reading GIF data: %s",
9162 build_string (errstr));
9163 else
9164 #endif
9165 if (NILP (specified_data))
9166 image_error ("Error reading `%s'", img->spec);
9167 else
9168 image_error ("Error reading GIF data");
9169 goto gif_error;
9170 }
9171
9172 width = img->width = gif->SWidth;
9173 height = img->height = gif->SHeight;
9174
9175
9176
9177 for (j = 0; j < gif->ImageCount; ++j)
9178 {
9179 struct SavedImage *subimage = gif->SavedImages + j;
9180 int subimg_width = subimage->ImageDesc.Width;
9181 int subimg_height = subimage->ImageDesc.Height;
9182 int subimg_top = subimage->ImageDesc.Top;
9183 int subimg_left = subimage->ImageDesc.Left;
9184 if (subimg_width < 0
9185 || subimg_height < 0
9186 || subimg_top < 0
9187 || subimg_left < 0
9188 || subimg_top + subimg_height > height
9189 || subimg_left + subimg_width > width)
9190 {
9191 image_error ("Subimage does not fit in image");
9192 goto gif_error;
9193 }
9194 }
9195 }
9196 else
9197 {
9198
9199 width = img->width = gif->SWidth;
9200 height = img->height = gif->SHeight;
9201 }
9202
9203 if (idx < 0 || idx >= gif->ImageCount)
9204 {
9205 image_error ("Invalid image number `%s' in image `%s'",
9206 make_fixnum (idx), img->spec);
9207 goto gif_error;
9208 }
9209
9210
9211 if (cache && !cache->handle)
9212 {
9213 cache->handle = gif;
9214 cache->destructor = (void (*)(void *)) &gif_destroy;
9215 cache->width = width;
9216 cache->height = height;
9217 cache->byte_size = byte_size;
9218 }
9219
9220 img->corners[TOP_CORNER] = gif->SavedImages[0].ImageDesc.Top;
9221 img->corners[LEFT_CORNER] = gif->SavedImages[0].ImageDesc.Left;
9222 img->corners[BOT_CORNER]
9223 = img->corners[TOP_CORNER] + gif->SavedImages[0].ImageDesc.Height;
9224 img->corners[RIGHT_CORNER]
9225 = img->corners[LEFT_CORNER] + gif->SavedImages[0].ImageDesc.Width;
9226
9227 if (!check_image_size (f, width, height))
9228 {
9229 image_size_error ();
9230 goto gif_error;
9231 }
9232
9233
9234 Emacs_Pix_Container ximg;
9235 if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, 0))
9236 goto gif_error;
9237
9238
9239
9240 if (!pixmap)
9241 {
9242 pixmap = xmalloc (width * height * sizeof (unsigned long));
9243 if (cache)
9244 cache->temp = pixmap;
9245 }
9246
9247
9248
9249
9250
9251 unsigned long frame_bg;
9252 #ifndef USE_CAIRO
9253 frame_bg = FRAME_BACKGROUND_PIXEL (f);
9254 #else
9255 {
9256 Emacs_Color color;
9257 FRAME_TERMINAL (f)->query_frame_background_color (f, &color);
9258 frame_bg = lookup_rgb_color (f, color.red, color.green, color.blue);
9259 }
9260 #endif
9261
9262 for (y = 0; y < img->corners[TOP_CORNER]; ++y)
9263 for (x = 0; x < width; ++x)
9264 *(pixmap + x + y * width) = frame_bg;
9265
9266 for (y = img->corners[BOT_CORNER]; y < height; ++y)
9267 for (x = 0; x < width; ++x)
9268 *(pixmap + x + y * width) = frame_bg;
9269
9270 for (y = img->corners[TOP_CORNER]; y < img->corners[BOT_CORNER]; ++y)
9271 {
9272 for (x = 0; x < img->corners[LEFT_CORNER]; ++x)
9273 *(pixmap + x + y * width) = frame_bg;
9274 for (x = img->corners[RIGHT_CORNER]; x < width; ++x)
9275 *(pixmap + x + y * width) = frame_bg;
9276 }
9277
9278
9279
9280 init_color_table ();
9281
9282 unsigned long bgcolor UNINIT;
9283 if (STRINGP (specified_bg))
9284 {
9285 bgcolor = image_alloc_image_color (f, img, specified_bg,
9286 FRAME_BACKGROUND_PIXEL (f));
9287 #ifdef USE_CAIRO
9288 Emacs_Color color = {.pixel = bgcolor};
9289 FRAME_TERMINAL (f)->query_colors (f, &color, 1);
9290 bgcolor = lookup_rgb_color (f, color.red, color.green, color.blue);
9291 #endif
9292 }
9293
9294 int start_frame = 0;
9295
9296
9297 if (cache && cache->temp)
9298 {
9299 start_frame = cache->index + 1;
9300 if (start_frame > idx)
9301 start_frame = 0;
9302 cache->index = idx;
9303 }
9304
9305 for (j = start_frame; j <= idx; ++j)
9306 {
9307
9308
9309 struct SavedImage *subimage = gif->SavedImages + j;
9310 unsigned char *raster = (unsigned char *) subimage->RasterBits;
9311 int subimg_width = subimage->ImageDesc.Width;
9312 int subimg_height = subimage->ImageDesc.Height;
9313 int subimg_top = subimage->ImageDesc.Top;
9314 int subimg_left = subimage->ImageDesc.Left;
9315
9316
9317
9318 int disposal = DISPOSAL_UNSPECIFIED;
9319 int transparency_color_index = NO_TRANSPARENT_COLOR;
9320
9321 #if GIFLIB_MAJOR < 5
9322
9323
9324 for (i = 0; i < subimage->ExtensionBlockCount; i++)
9325 {
9326 ExtensionBlock *extblock = subimage->ExtensionBlocks + i;
9327
9328 if ((extblock->Function == GIF_LOCAL_DESCRIPTOR_EXTENSION)
9329 && extblock->ByteCount == 4
9330 && extblock->Bytes[0] & 1)
9331 {
9332 disposal = (extblock->Bytes[0] >> 2) & 7;
9333 transparency_color_index = (unsigned char) extblock->Bytes[3];
9334 break;
9335 }
9336 }
9337 #else
9338 GraphicsControlBlock gcb;
9339 DGifSavedExtensionToGCB (gif, j, &gcb);
9340 disposal = gcb.DisposalMode;
9341 transparency_color_index = gcb.TransparentColor;
9342 #endif
9343
9344
9345 if (j == 0)
9346 disposal = DISPOSE_BACKGROUND;
9347
9348
9349
9350
9351
9352
9353 if (disposal == DISPOSAL_UNSPECIFIED)
9354 disposal = DISPOSE_DO_NOT;
9355
9356
9357
9358
9359
9360
9361 if (disposal == DISPOSE_PREVIOUS)
9362 disposal = DISPOSE_DO_NOT;
9363
9364 gif_color_map = subimage->ImageDesc.ColorMap;
9365 if (!gif_color_map)
9366 gif_color_map = gif->SColorMap;
9367
9368
9369 unsigned long pixel_colors[256] = { 0, };
9370
9371 if (gif_color_map)
9372 for (i = 0; i < gif_color_map->ColorCount; ++i)
9373 {
9374 if (transparency_color_index == i)
9375 pixel_colors[i] = STRINGP (specified_bg)
9376 ? bgcolor : frame_bg;
9377 else
9378 {
9379 int r = gif_color_map->Colors[i].Red << 8;
9380 int g = gif_color_map->Colors[i].Green << 8;
9381 int b = gif_color_map->Colors[i].Blue << 8;
9382 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
9383 }
9384 }
9385
9386
9387 if (GIFLIB_MAJOR < 5 && gif->SavedImages[j].ImageDesc.Interlace)
9388 {
9389 int row, pass;
9390
9391 for (y = 0, row = interlace_start[0], pass = 0;
9392 y < subimg_height;
9393 y++, row += interlace_increment[pass])
9394 {
9395 while (subimg_height <= row)
9396 row = interlace_start[++pass];
9397
9398 for (x = 0; x < subimg_width; x++)
9399 {
9400 int c = raster[y * subimg_width + x];
9401 if (transparency_color_index != c || disposal != DISPOSE_DO_NOT)
9402 {
9403 *(pixmap + x + subimg_left + (y + subimg_top) * width) =
9404 pixel_colors[c];
9405 }
9406 }
9407 }
9408 }
9409 else
9410 {
9411 for (y = 0; y < subimg_height; ++y)
9412 for (x = 0; x < subimg_width; ++x)
9413 {
9414 int c = raster[y * subimg_width + x];
9415 if (transparency_color_index != c || disposal != DISPOSE_DO_NOT)
9416 {
9417 *(pixmap + x + subimg_left + (y + subimg_top) * width) =
9418 pixel_colors[c];
9419 }
9420 }
9421 }
9422 }
9423
9424
9425
9426 for (y = 0; y < height; ++y)
9427 for (x = 0; x < width; ++x)
9428 PUT_PIXEL (ximg, x, y, *(pixmap + x + y * width));
9429
9430 #ifdef COLOR_TABLE_SUPPORT
9431 img->colors = colors_in_color_table (&img->ncolors);
9432 free_color_table ();
9433 #endif
9434
9435
9436
9437 img->lisp_data = Qnil;
9438 if (gif->SavedImages[idx].ExtensionBlockCount > 0)
9439 {
9440 int delay = 0;
9441 ExtensionBlock *ext = gif->SavedImages[idx].ExtensionBlocks;
9442 for (i = 0; i < gif->SavedImages[idx].ExtensionBlockCount; i++, ext++)
9443
9444 {
9445 img->lisp_data
9446 = Fcons (make_fixnum (ext->Function),
9447 Fcons (make_unibyte_string ((char *) ext->Bytes,
9448 ext->ByteCount),
9449 img->lisp_data));
9450 if (ext->Function == GIF_LOCAL_DESCRIPTOR_EXTENSION
9451 && ext->ByteCount == 4)
9452 {
9453 delay = ext->Bytes[2] << CHAR_BIT;
9454 delay |= ext->Bytes[1];
9455 }
9456 }
9457 img->lisp_data = list2 (Qextension_data, img->lisp_data);
9458 img->lisp_data
9459 = Fcons (Qdelay,
9460
9461 Fcons (make_float (delay? delay / 100.0: 1.0 / 15),
9462 img->lisp_data));
9463 }
9464
9465 if (gif->ImageCount > 1)
9466 img->lisp_data = Fcons (Qcount,
9467 Fcons (make_fixnum (gif->ImageCount),
9468 img->lisp_data));
9469
9470 if (!cache)
9471 {
9472 if (pixmap)
9473 xfree (pixmap);
9474 if (gif_close (gif, &gif_err) == GIF_ERROR)
9475 {
9476 #if HAVE_GIFERRORSTRING
9477 char const *error_text = GifErrorString (gif_err);
9478
9479 if (error_text)
9480 image_error ("Error closing `%s': %s",
9481 img->spec, build_string (error_text));
9482 else
9483 #endif
9484 image_error ("Error closing `%s'", img->spec);
9485 }
9486 }
9487
9488
9489 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
9490
9491 IMAGE_BACKGROUND (img, f, (Emacs_Pix_Context)ximg);
9492
9493
9494 image_put_x_image (f, img, ximg, 0);
9495
9496 return true;
9497
9498 gif_error:
9499 if (pixmap)
9500 xfree (pixmap);
9501 gif_close (gif, NULL);
9502 if (cache)
9503 {
9504 cache->handle = NULL;
9505 cache->temp = NULL;
9506 }
9507 return false;
9508 }
9509
9510 #endif
9511
9512
9513 #ifdef HAVE_WEBP
9514
9515
9516
9517
9518
9519
9520 #include "webp/decode.h"
9521 #include "webp/demux.h"
9522
9523
9524
9525 enum webp_keyword_index
9526 {
9527 WEBP_TYPE,
9528 WEBP_DATA,
9529 WEBP_FILE,
9530 WEBP_ASCENT,
9531 WEBP_MARGIN,
9532 WEBP_RELIEF,
9533 WEBP_ALGORITHM,
9534 WEBP_HEURISTIC_MASK,
9535 WEBP_MASK,
9536 WEBP_INDEX,
9537 WEBP_BACKGROUND,
9538 WEBP_LAST
9539 };
9540
9541
9542
9543
9544 static const struct image_keyword webp_format[WEBP_LAST] =
9545 {
9546 {":type", IMAGE_SYMBOL_VALUE, 1},
9547 {":data", IMAGE_STRING_VALUE, 0},
9548 {":file", IMAGE_STRING_VALUE, 0},
9549 {":ascent", IMAGE_ASCENT_VALUE, 0},
9550 {":margin", IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR, 0},
9551 {":relief", IMAGE_INTEGER_VALUE, 0},
9552 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9553 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9554 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9555 {":index", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
9556 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
9557 };
9558
9559
9560
9561 static bool
9562 webp_image_p (Lisp_Object object)
9563 {
9564 struct image_keyword fmt[WEBP_LAST];
9565 memcpy (fmt, webp_format, sizeof fmt);
9566
9567 if (!parse_image_spec (object, fmt, WEBP_LAST, Qwebp))
9568 return false;
9569
9570
9571 return fmt[WEBP_FILE].count + fmt[WEBP_DATA].count == 1;
9572 }
9573
9574 #ifdef WINDOWSNT
9575
9576
9577
9578 DEF_DLL_FN (int, WebPGetInfo, (const uint8_t *, size_t, int *, int *));
9579
9580
9581
9582
9583 DEF_DLL_FN (VP8StatusCode, WebPGetFeaturesInternal,
9584 (const uint8_t *, size_t, WebPBitstreamFeatures *, int));
9585 DEF_DLL_FN (uint8_t *, WebPDecodeRGBA, (const uint8_t *, size_t, int *, int *));
9586 DEF_DLL_FN (uint8_t *, WebPDecodeRGB, (const uint8_t *, size_t, int *, int *));
9587 DEF_DLL_FN (void, WebPFree, (void *));
9588 DEF_DLL_FN (uint32_t, WebPDemuxGetI, (const WebPDemuxer *, WebPFormatFeature));
9589 DEF_DLL_FN (WebPDemuxer *, WebPDemuxInternal,
9590 (const WebPData *, int, WebPDemuxState *, int));
9591 DEF_DLL_FN (void, WebPDemuxDelete, (WebPDemuxer *));
9592 DEF_DLL_FN (int, WebPAnimDecoderGetNext,
9593 (WebPAnimDecoder *, uint8_t **, int *));
9594 DEF_DLL_FN (WebPAnimDecoder *, WebPAnimDecoderNewInternal,
9595 (const WebPData *, const WebPAnimDecoderOptions *, int));
9596 DEF_DLL_FN (int, WebPAnimDecoderOptionsInitInternal,
9597 (WebPAnimDecoderOptions *, int));
9598 DEF_DLL_FN (int, WebPAnimDecoderHasMoreFrames, (const WebPAnimDecoder *));
9599 DEF_DLL_FN (void, WebPAnimDecoderDelete, (WebPAnimDecoder *));
9600
9601 static bool
9602 init_webp_functions (void)
9603 {
9604 HMODULE library1, library2;
9605
9606 if (!((library1 = w32_delayed_load (Qwebp))
9607 && (library2 = w32_delayed_load (Qwebpdemux))))
9608 return false;
9609
9610 LOAD_DLL_FN (library1, WebPGetInfo);
9611 LOAD_DLL_FN (library1, WebPGetFeaturesInternal);
9612 LOAD_DLL_FN (library1, WebPDecodeRGBA);
9613 LOAD_DLL_FN (library1, WebPDecodeRGB);
9614 LOAD_DLL_FN (library1, WebPFree);
9615 LOAD_DLL_FN (library2, WebPDemuxGetI);
9616 LOAD_DLL_FN (library2, WebPDemuxInternal);
9617 LOAD_DLL_FN (library2, WebPDemuxDelete);
9618 LOAD_DLL_FN (library2, WebPAnimDecoderGetNext);
9619 LOAD_DLL_FN (library2, WebPAnimDecoderNewInternal);
9620 LOAD_DLL_FN (library2, WebPAnimDecoderOptionsInitInternal);
9621 LOAD_DLL_FN (library2, WebPAnimDecoderHasMoreFrames);
9622 LOAD_DLL_FN (library2, WebPAnimDecoderDelete);
9623 return true;
9624 }
9625
9626 #undef WebPGetInfo
9627 #undef WebPGetFeatures
9628 #undef WebPDecodeRGBA
9629 #undef WebPDecodeRGB
9630 #undef WebPFree
9631 #undef WebPDemuxGetI
9632 #undef WebPDemux
9633 #undef WebPDemuxDelete
9634 #undef WebPAnimDecoderGetNext
9635 #undef WebPAnimDecoderNew
9636 #undef WebPAnimDecoderOptionsInit
9637 #undef WebPAnimDecoderHasMoreFrames
9638 #undef WebPAnimDecoderDelete
9639
9640 #define WebPGetInfo fn_WebPGetInfo
9641 #define WebPGetFeatures(d,s,f) \
9642 fn_WebPGetFeaturesInternal(d,s,f,WEBP_DECODER_ABI_VERSION)
9643 #define WebPDecodeRGBA fn_WebPDecodeRGBA
9644 #define WebPDecodeRGB fn_WebPDecodeRGB
9645 #define WebPFree fn_WebPFree
9646 #define WebPDemuxGetI fn_WebPDemuxGetI
9647 #define WebPDemux(d) \
9648 fn_WebPDemuxInternal(d,0,NULL,WEBP_DEMUX_ABI_VERSION)
9649 #define WebPDemuxDelete fn_WebPDemuxDelete
9650 #define WebPAnimDecoderGetNext fn_WebPAnimDecoderGetNext
9651 #define WebPAnimDecoderNew(d,o) \
9652 fn_WebPAnimDecoderNewInternal(d,o,WEBP_DEMUX_ABI_VERSION)
9653 #define WebPAnimDecoderOptionsInit(o) \
9654 fn_WebPAnimDecoderOptionsInitInternal(o,WEBP_DEMUX_ABI_VERSION)
9655 #define WebPAnimDecoderHasMoreFrames fn_WebPAnimDecoderHasMoreFrames
9656 #define WebPAnimDecoderDelete fn_WebPAnimDecoderDelete
9657
9658 #endif
9659
9660 static void
9661 webp_destroy (struct anim_cache* cache)
9662 {
9663 WebPAnimDecoderDelete (cache->handle);
9664 }
9665
9666
9667
9668
9669 static bool
9670 webp_load (struct frame *f, struct image *img)
9671 {
9672 ptrdiff_t size = 0;
9673 uint8_t *contents;
9674 Lisp_Object file = Qnil;
9675 int frames = 0;
9676 double delay = 0;
9677 WebPAnimDecoder* anim = NULL;
9678
9679
9680 Lisp_Object specified_file = image_spec_value (img->spec, QCfile, NULL);
9681 Lisp_Object specified_data = image_spec_value (img->spec, QCdata, NULL);
9682
9683 if (NILP (specified_data))
9684 {
9685 int fd;
9686 file = image_find_image_fd (specified_file, &fd);
9687 if (!STRINGP (file))
9688 {
9689 image_error ("Cannot find image file `%s'", specified_file);
9690 return false;
9691 }
9692
9693 contents = (uint8_t *) slurp_file (fd, &size);
9694 if (contents == NULL)
9695 {
9696 image_error ("Error loading WebP image `%s'", file);
9697 return false;
9698 }
9699 }
9700 else
9701 {
9702 if (!STRINGP (specified_data))
9703 {
9704 image_error ("Invalid image data `%s'", specified_data);
9705 return false;
9706 }
9707 contents = SDATA (specified_data);
9708 size = SBYTES (specified_data);
9709 }
9710
9711
9712 if (!WebPGetInfo (contents, size, NULL, NULL))
9713 {
9714 if (!NILP (file))
9715 image_error ("Not a WebP file: `%s'", file);
9716 else
9717 image_error ("Invalid header in WebP image data");
9718 goto webp_error1;
9719 }
9720
9721 Lisp_Object image_number = image_spec_value (img->spec, QCindex, NULL);
9722 ptrdiff_t idx = FIXNUMP (image_number) ? XFIXNAT (image_number) : 0;
9723
9724
9725 WebPBitstreamFeatures features;
9726 VP8StatusCode result = WebPGetFeatures (contents, size, &features);
9727 switch (result)
9728 {
9729 case VP8_STATUS_OK:
9730 break;
9731 case VP8_STATUS_NOT_ENOUGH_DATA:
9732 case VP8_STATUS_OUT_OF_MEMORY:
9733 case VP8_STATUS_INVALID_PARAM:
9734 case VP8_STATUS_BITSTREAM_ERROR:
9735 case VP8_STATUS_UNSUPPORTED_FEATURE:
9736 case VP8_STATUS_SUSPENDED:
9737 case VP8_STATUS_USER_ABORT:
9738 default:
9739
9740 if (!NILP (file))
9741 image_error ("Error when interpreting WebP image data: `%s'", file);
9742 else
9743 image_error ("Error when interpreting WebP image data");
9744 goto webp_error1;
9745 }
9746
9747 uint8_t *decoded = NULL;
9748 int width, height;
9749
9750 if (features.has_animation)
9751 {
9752
9753 int timestamp;
9754
9755 struct anim_cache* cache = anim_get_animation_cache (XCDR (img->spec));
9756
9757 if (cache->handle && cache->index == idx - 1)
9758 {
9759 WebPAnimDecoderGetNext (cache->handle, &decoded, ×tamp);
9760 delay = timestamp;
9761 cache->index++;
9762 anim = cache->handle;
9763 width = cache->width;
9764 height = cache->height;
9765 frames = cache->frames;
9766 }
9767 else
9768 {
9769
9770 if (cache->handle)
9771 WebPAnimDecoderDelete (cache->handle);
9772
9773 WebPData webp_data;
9774 if (NILP (specified_data))
9775
9776
9777 webp_data.bytes = cache->temp = contents;
9778 else
9779
9780
9781 {
9782 webp_data.bytes = xmalloc (size);
9783 memcpy ((void*) webp_data.bytes, contents, size);
9784 }
9785
9786
9787 webp_data.size = size;
9788
9789
9790 cache->byte_size = size;
9791
9792
9793 WebPDemuxer* demux = WebPDemux (&webp_data);
9794 cache->width = width = WebPDemuxGetI (demux, WEBP_FF_CANVAS_WIDTH);
9795 cache->height = height = WebPDemuxGetI (demux,
9796 WEBP_FF_CANVAS_HEIGHT);
9797 cache->frames = frames = WebPDemuxGetI (demux, WEBP_FF_FRAME_COUNT);
9798 cache->destructor = (void (*)(void *)) webp_destroy;
9799 WebPDemuxDelete (demux);
9800
9801 WebPAnimDecoderOptions dec_options;
9802 WebPAnimDecoderOptionsInit (&dec_options);
9803 anim = WebPAnimDecoderNew (&webp_data, &dec_options);
9804
9805 cache->handle = anim;
9806 cache->index = idx;
9807
9808 while (WebPAnimDecoderHasMoreFrames (anim)) {
9809 WebPAnimDecoderGetNext (anim, &decoded, ×tamp);
9810
9811
9812 if (delay == 0)
9813 delay = timestamp;
9814
9815 if (idx-- == 0)
9816 break;
9817 }
9818 }
9819 }
9820 else
9821 {
9822
9823 if (features.has_alpha)
9824
9825 decoded = WebPDecodeRGBA (contents, size, &width, &height);
9826 else
9827
9828 decoded = WebPDecodeRGB (contents, size, &width, &height);
9829 }
9830
9831 if (!decoded)
9832 {
9833 image_error ("Error when decoding WebP image data");
9834 goto webp_error1;
9835 }
9836
9837 if (!(width <= INT_MAX && height <= INT_MAX
9838 && check_image_size (f, width, height)))
9839 {
9840 image_size_error ();
9841 goto webp_error2;
9842 }
9843
9844
9845 Emacs_Pix_Container ximg, mask_img = NULL;
9846 if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, false))
9847 goto webp_error2;
9848
9849
9850
9851 if (features.has_alpha
9852 && !image_create_x_image_and_pixmap (f, img, width, height, 1,
9853 &mask_img, true))
9854 {
9855 image_destroy_x_image (ximg);
9856 image_clear_image_1 (f, img, CLEAR_IMAGE_PIXMAP);
9857 goto webp_error2;
9858 }
9859
9860
9861 init_color_table ();
9862
9863 img->corners[TOP_CORNER] = 0;
9864 img->corners[LEFT_CORNER] = 0;
9865 img->corners[BOT_CORNER]
9866 = img->corners[TOP_CORNER] + height;
9867 img->corners[RIGHT_CORNER]
9868 = img->corners[LEFT_CORNER] + width;
9869
9870 uint8_t *p = decoded;
9871 for (int y = 0; y < height; ++y)
9872 {
9873 for (int x = 0; x < width; ++x)
9874 {
9875 int r = *p++ << 8;
9876 int g = *p++ << 8;
9877 int b = *p++ << 8;
9878 PUT_PIXEL (ximg, x, y, lookup_rgb_color (f, r, g, b));
9879
9880
9881
9882
9883
9884 if (features.has_alpha || anim)
9885 {
9886 if (mask_img)
9887 PUT_PIXEL (mask_img, x, y, *p > 0 ? PIX_MASK_DRAW : PIX_MASK_RETAIN);
9888 ++p;
9889 }
9890 }
9891 }
9892
9893 #ifdef COLOR_TABLE_SUPPORT
9894
9895 img->colors = colors_in_color_table (&img->ncolors);
9896 free_color_table ();
9897 #endif
9898
9899
9900 image_put_x_image (f, img, ximg, 0);
9901
9902
9903 if (mask_img)
9904 {
9905
9906
9907 image_background_transparent (img, f, (Emacs_Pix_Context)mask_img);
9908
9909 image_put_x_image (f, img, mask_img, 1);
9910 }
9911
9912 img->width = width;
9913 img->height = height;
9914
9915
9916 img->lisp_data = Fcons (Qcount,
9917 Fcons (make_fixnum (frames),
9918 img->lisp_data));
9919 img->lisp_data = Fcons (Qdelay,
9920 Fcons (make_float (delay / 1000),
9921 img->lisp_data));
9922
9923
9924 if (!anim)
9925 WebPFree (decoded);
9926 if (NILP (specified_data) && !anim)
9927 xfree (contents);
9928 return true;
9929
9930 webp_error2:
9931 if (!anim)
9932 WebPFree (decoded);
9933
9934 webp_error1:
9935 if (NILP (specified_data))
9936 xfree (contents);
9937 return false;
9938 }
9939
9940 #endif
9941
9942
9943 #ifdef HAVE_IMAGEMAGICK
9944
9945
9946
9947
9948
9949
9950
9951
9952 enum imagemagick_keyword_index
9953 {
9954 IMAGEMAGICK_TYPE,
9955 IMAGEMAGICK_DATA,
9956 IMAGEMAGICK_FILE,
9957 IMAGEMAGICK_ASCENT,
9958 IMAGEMAGICK_MARGIN,
9959 IMAGEMAGICK_RELIEF,
9960 IMAGEMAGICK_ALGORITHM,
9961 IMAGEMAGICK_HEURISTIC_MASK,
9962 IMAGEMAGICK_MASK,
9963 IMAGEMAGICK_BACKGROUND,
9964 IMAGEMAGICK_HEIGHT,
9965 IMAGEMAGICK_WIDTH,
9966 IMAGEMAGICK_MAX_HEIGHT,
9967 IMAGEMAGICK_MAX_WIDTH,
9968 IMAGEMAGICK_FORMAT,
9969 IMAGEMAGICK_ROTATION,
9970 IMAGEMAGICK_CROP,
9971 IMAGEMAGICK_LAST
9972 };
9973
9974
9975
9976
9977 static struct image_keyword imagemagick_format[IMAGEMAGICK_LAST] =
9978 {
9979 {":type", IMAGE_SYMBOL_VALUE, 1},
9980 {":data", IMAGE_STRING_VALUE, 0},
9981 {":file", IMAGE_STRING_VALUE, 0},
9982 {":ascent", IMAGE_ASCENT_VALUE, 0},
9983 {":margin", IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR, 0},
9984 {":relief", IMAGE_INTEGER_VALUE, 0},
9985 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9986 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9987 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9988 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
9989 {":height", IMAGE_INTEGER_VALUE, 0},
9990 {":width", IMAGE_INTEGER_VALUE, 0},
9991 {":max-height", IMAGE_INTEGER_VALUE, 0},
9992 {":max-width", IMAGE_INTEGER_VALUE, 0},
9993 {":format", IMAGE_SYMBOL_VALUE, 0},
9994 {":rotation", IMAGE_NUMBER_VALUE, 0},
9995 {":crop", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
9996 };
9997
9998
9999
10000 static void
10001 imagemagick_clear_image (struct frame *f,
10002 struct image *img)
10003 {
10004 image_clear_image (f, img);
10005 }
10006
10007
10008
10009
10010
10011 static bool
10012 imagemagick_image_p (Lisp_Object object)
10013 {
10014 struct image_keyword fmt[IMAGEMAGICK_LAST];
10015 memcpy (fmt, imagemagick_format, sizeof fmt);
10016
10017 if (!parse_image_spec (object, fmt, IMAGEMAGICK_LAST, Qimagemagick))
10018 return 0;
10019
10020
10021 return fmt[IMAGEMAGICK_FILE].count + fmt[IMAGEMAGICK_DATA].count == 1;
10022 }
10023
10024
10025
10026 #define DrawRectangle DrawRectangleGif
10027
10028 #ifdef HAVE_IMAGEMAGICK7
10029 # include <MagickWand/MagickWand.h>
10030 # include <MagickCore/version.h>
10031
10032 # define PixelSetMagickColor PixelSetPixelColor
10033 typedef PixelInfo MagickPixelPacket;
10034 #else
10035 # include <wand/MagickWand.h>
10036 # include <magick/version.h>
10037 #endif
10038
10039
10040
10041 #if 0x653 <= MagickLibVersion && MagickLibVersion <= 0x665
10042 extern WandExport void PixelGetMagickColor (const PixelWand *,
10043 MagickPixelPacket *);
10044 #endif
10045
10046 static void
10047 imagemagick_initialize (void)
10048 {
10049 static bool imagemagick_initialized;
10050 if (!imagemagick_initialized)
10051 {
10052 imagemagick_initialized = true;
10053 MagickWandGenesis ();
10054 }
10055 }
10056
10057
10058
10059
10060 static void
10061 imagemagick_error (MagickWand *wand)
10062 {
10063 char *description;
10064 ExceptionType severity;
10065
10066 description = MagickGetException (wand, &severity);
10067 image_error ("ImageMagick error: %s", build_string (description));
10068 MagickRelinquishMemory (description);
10069 }
10070
10071
10072
10073
10074 static char *
10075 imagemagick_filename_hint (Lisp_Object spec, char hint_buffer[MaxTextExtent])
10076 {
10077 Lisp_Object symbol = intern ("image-format-suffixes");
10078 Lisp_Object val = find_symbol_value (symbol);
10079 Lisp_Object format;
10080
10081 if (! CONSP (val))
10082 return NULL;
10083
10084 format = image_spec_value (spec, intern (":format"), NULL);
10085 val = Fcar_safe (Fcdr_safe (Fassq (format, val)));
10086 if (! STRINGP (val))
10087 return NULL;
10088
10089
10090
10091 snprintf (hint_buffer, MaxTextExtent, "/tmp/foo.%s", SSDATA (val));
10092 return hint_buffer;
10093 }
10094
10095
10096
10097
10098
10099
10100
10101
10102
10103
10104
10105
10106
10107 struct animation_cache
10108 {
10109 MagickWand *wand;
10110 int index;
10111 struct timespec update_time;
10112 struct animation_cache *next;
10113 char signature[FLEXIBLE_ARRAY_MEMBER];
10114 };
10115
10116 static struct animation_cache *animation_cache = NULL;
10117
10118 static struct animation_cache *
10119 imagemagick_create_cache (char *signature)
10120 {
10121 struct animation_cache *cache
10122 = xmalloc (FLEXSIZEOF (struct animation_cache, signature,
10123 strlen (signature) + 1));
10124 cache->wand = 0;
10125 cache->index = 0;
10126 cache->next = 0;
10127 strcpy (cache->signature, signature);
10128 return cache;
10129 }
10130
10131
10132
10133 static void
10134 imagemagick_prune_animation_cache (bool clear)
10135 {
10136 struct animation_cache **pcache = &animation_cache;
10137 struct timespec old = timespec_sub (current_timespec (),
10138 make_timespec (60, 0));
10139
10140 while (*pcache)
10141 {
10142 struct animation_cache *cache = *pcache;
10143 if (clear || timespec_cmp (old, cache->update_time) > 0)
10144 {
10145 if (cache->wand)
10146 DestroyMagickWand (cache->wand);
10147 *pcache = cache->next;
10148 xfree (cache);
10149 }
10150 else
10151 pcache = &cache->next;
10152 }
10153 }
10154
10155 static struct animation_cache *
10156 imagemagick_get_animation_cache (MagickWand *wand)
10157 {
10158 char *signature = MagickGetImageSignature (wand);
10159 struct animation_cache *cache;
10160 struct animation_cache **pcache = &animation_cache;
10161
10162 imagemagick_prune_animation_cache (false);
10163
10164 while (1)
10165 {
10166 cache = *pcache;
10167 if (! cache)
10168 {
10169 *pcache = cache = imagemagick_create_cache (signature);
10170 break;
10171 }
10172 if (strcmp (signature, cache->signature) == 0)
10173 break;
10174 pcache = &cache->next;
10175 }
10176
10177 DestroyString (signature);
10178 cache->update_time = current_timespec ();
10179 return cache;
10180 }
10181
10182 static MagickWand *
10183 imagemagick_compute_animated_image (MagickWand *super_wand, int ino)
10184 {
10185 int i;
10186 MagickWand *composite_wand;
10187 size_t dest_width, dest_height;
10188 struct animation_cache *cache = imagemagick_get_animation_cache (super_wand);
10189
10190 MagickSetIteratorIndex (super_wand, 0);
10191
10192 if (ino == 0 || cache->wand == NULL || cache->index > ino)
10193 {
10194 composite_wand = MagickGetImage (super_wand);
10195 if (cache->wand)
10196 DestroyMagickWand (cache->wand);
10197 }
10198 else
10199 composite_wand = cache->wand;
10200
10201 dest_height = MagickGetImageHeight (composite_wand);
10202
10203 for (i = max (1, cache->index + 1); i <= ino; i++)
10204 {
10205 MagickWand *sub_wand;
10206 PixelIterator *source_iterator, *dest_iterator;
10207 PixelWand **source, **dest;
10208 size_t source_width, source_height;
10209 ssize_t source_left, source_top;
10210 MagickPixelPacket pixel;
10211 DisposeType dispose;
10212 ptrdiff_t lines = 0;
10213
10214 MagickSetIteratorIndex (super_wand, i);
10215 sub_wand = MagickGetImage (super_wand);
10216
10217 MagickGetImagePage (sub_wand, &source_width, &source_height,
10218 &source_left, &source_top);
10219
10220
10221 dispose = MagickGetImageDispose (sub_wand);
10222
10223 source_iterator = NewPixelIterator (sub_wand);
10224 if (! source_iterator)
10225 {
10226 DestroyMagickWand (composite_wand);
10227 DestroyMagickWand (sub_wand);
10228 cache->wand = NULL;
10229 image_error ("Imagemagick pixel iterator creation failed");
10230 return NULL;
10231 }
10232
10233 dest_iterator = NewPixelIterator (composite_wand);
10234 if (! dest_iterator)
10235 {
10236 DestroyMagickWand (composite_wand);
10237 DestroyMagickWand (sub_wand);
10238 DestroyPixelIterator (source_iterator);
10239 cache->wand = NULL;
10240 image_error ("Imagemagick pixel iterator creation failed");
10241 return NULL;
10242 }
10243
10244
10245
10246 if (source_top > 0)
10247 {
10248 PixelSetIteratorRow (dest_iterator, source_top);
10249 lines = source_top;
10250 }
10251
10252 while ((source = PixelGetNextIteratorRow (source_iterator, &source_width))
10253 != NULL)
10254 {
10255 ptrdiff_t x;
10256
10257
10258
10259 if (++lines >= dest_height)
10260 break;
10261
10262 dest = PixelGetNextIteratorRow (dest_iterator, &dest_width);
10263 for (x = 0; x < source_width; x++)
10264 {
10265
10266
10267 if (x + source_left >= dest_width)
10268 break;
10269
10270
10271
10272 if (dispose == BackgroundDispose || PixelGetAlpha (source[x]))
10273 {
10274 PixelGetMagickColor (source[x], &pixel);
10275 PixelSetMagickColor (dest[x + source_left], &pixel);
10276 }
10277 }
10278 PixelSyncIterator (dest_iterator);
10279 }
10280
10281 DestroyPixelIterator (source_iterator);
10282 DestroyPixelIterator (dest_iterator);
10283 DestroyMagickWand (sub_wand);
10284 }
10285
10286
10287
10288 cache->wand = CloneMagickWand (composite_wand);
10289 cache->index = ino;
10290
10291 return composite_wand;
10292 }
10293
10294
10295
10296
10297
10298
10299
10300
10301
10302
10303
10304
10305
10306
10307 static bool
10308 imagemagick_load_image (struct frame *f, struct image *img,
10309 unsigned char *contents, unsigned int size,
10310 char *filename)
10311 {
10312 int width, height;
10313 size_t image_width, image_height;
10314 MagickBooleanType status;
10315 Emacs_Pix_Container ximg;
10316 int x, y;
10317 MagickWand *image_wand;
10318 PixelIterator *iterator;
10319 PixelWand **pixels, *bg_wand = NULL;
10320 MagickPixelPacket pixel;
10321 Lisp_Object image;
10322 #ifndef DONT_CREATE_TRANSFORMED_IMAGEMAGICK_IMAGE
10323 Lisp_Object value;
10324 #endif
10325 Lisp_Object crop;
10326 EMACS_INT ino;
10327 int desired_width, desired_height;
10328 #ifndef DONT_CREATE_TRANSFORMED_IMAGEMAGICK_IMAGE
10329 double rotation;
10330 #endif
10331 char hint_buffer[MaxTextExtent];
10332 char *filename_hint = NULL;
10333 imagemagick_initialize ();
10334
10335
10336
10337
10338
10339
10340 image = image_spec_value (img->spec, QCindex, NULL);
10341 ino = FIXNUMP (image) ? XFIXNAT (image) : 0;
10342 image_wand = NewMagickWand ();
10343
10344 if (filename)
10345 status = MagickReadImage (image_wand, filename);
10346 else
10347 {
10348 Lisp_Object lwidth = image_spec_value (img->spec, QCwidth, NULL);
10349 Lisp_Object lheight = image_spec_value (img->spec, QCheight, NULL);
10350
10351 if (FIXNATP (lwidth) && FIXNATP (lheight))
10352 {
10353 MagickSetSize (image_wand, XFIXNAT (lwidth), XFIXNAT (lheight));
10354 MagickSetDepth (image_wand, 8);
10355 }
10356 filename_hint = imagemagick_filename_hint (img->spec, hint_buffer);
10357 MagickSetFilename (image_wand, filename_hint);
10358 status = MagickReadImageBlob (image_wand, contents, size);
10359 }
10360
10361 if (status == MagickFalse)
10362 {
10363 imagemagick_error (image_wand);
10364 DestroyMagickWand (image_wand);
10365 return 0;
10366 }
10367
10368 #ifdef HAVE_MAGICKAUTOORIENTIMAGE
10369
10370
10371 if (NILP (image_spec_value (img->spec, QCrotation, NULL)))
10372 if (MagickAutoOrientImage (image_wand) == MagickFalse)
10373 {
10374 image_error ("Error applying automatic orientation in image `%s'", img->spec);
10375 DestroyMagickWand (image_wand);
10376 return 0;
10377 }
10378 #endif
10379
10380 if (ino < 0 || ino >= MagickGetNumberImages (image_wand))
10381 {
10382 image_error ("Invalid image number `%s' in image `%s'", image, img->spec);
10383 DestroyMagickWand (image_wand);
10384 return 0;
10385 }
10386
10387 if (MagickGetImageDelay (image_wand) > 0)
10388 img->lisp_data =
10389 Fcons (Qdelay,
10390 Fcons (make_float (MagickGetImageDelay (image_wand) / 100.0),
10391 img->lisp_data));
10392
10393 if (MagickGetNumberImages (image_wand) > 1)
10394 img->lisp_data =
10395 Fcons (Qcount,
10396 Fcons (make_fixnum (MagickGetNumberImages (image_wand)),
10397 img->lisp_data));
10398
10399
10400
10401 if (MagickGetNumberImages (image_wand) > 1)
10402 {
10403
10404
10405 if (MagickGetImageDelay (image_wand) > 0)
10406 {
10407 MagickWand *super_wand = image_wand;
10408 image_wand = imagemagick_compute_animated_image (super_wand, ino);
10409 if (! image_wand)
10410 image_wand = super_wand;
10411 else
10412 DestroyMagickWand (super_wand);
10413 }
10414 else
10415
10416
10417
10418 {
10419 MagickWand *super_wand = image_wand;
10420
10421 MagickSetIteratorIndex (super_wand, ino);
10422 image_wand = MagickGetImage (super_wand);
10423 DestroyMagickWand (super_wand);
10424 }
10425 }
10426
10427
10428 {
10429 Emacs_Color bgcolor;
10430 Lisp_Object specified_bg;
10431
10432 specified_bg = image_spec_value (img->spec, QCbackground, NULL);
10433 if (!STRINGP (specified_bg)
10434 || !FRAME_TERMINAL (f)->defined_color_hook (f,
10435 SSDATA (specified_bg),
10436 &bgcolor,
10437 false,
10438 false))
10439 FRAME_TERMINAL (f)->query_frame_background_color (f, &bgcolor);
10440
10441 bg_wand = NewPixelWand ();
10442 PixelSetRed (bg_wand, (double) bgcolor.red / 65535);
10443 PixelSetGreen (bg_wand, (double) bgcolor.green / 65535);
10444 PixelSetBlue (bg_wand, (double) bgcolor.blue / 65535);
10445 }
10446
10447 #ifndef DONT_CREATE_TRANSFORMED_IMAGEMAGICK_IMAGE
10448 compute_image_size (MagickGetImageWidth (image_wand),
10449 MagickGetImageHeight (image_wand),
10450 img, &desired_width, &desired_height);
10451 #else
10452 desired_width = desired_height = -1;
10453 #endif
10454
10455 if (desired_width != -1 && desired_height != -1)
10456 {
10457 status = MagickScaleImage (image_wand, desired_width, desired_height);
10458 if (status == MagickFalse)
10459 {
10460 image_error ("Imagemagick scale failed");
10461 imagemagick_error (image_wand);
10462 goto imagemagick_error;
10463 }
10464 }
10465
10466
10467
10468 crop = image_spec_value (img->spec, QCcrop, NULL);
10469
10470 if (CONSP (crop) && TYPE_RANGED_FIXNUMP (size_t, XCAR (crop)))
10471 {
10472
10473
10474
10475
10476
10477 size_t crop_width = XFIXNUM (XCAR (crop));
10478 crop = XCDR (crop);
10479 if (CONSP (crop) && TYPE_RANGED_FIXNUMP (size_t, XCAR (crop)))
10480 {
10481 size_t crop_height = XFIXNUM (XCAR (crop));
10482 crop = XCDR (crop);
10483 if (CONSP (crop) && TYPE_RANGED_FIXNUMP (ssize_t, XCAR (crop)))
10484 {
10485 ssize_t crop_x = XFIXNUM (XCAR (crop));
10486 crop = XCDR (crop);
10487 if (CONSP (crop) && TYPE_RANGED_FIXNUMP (ssize_t, XCAR (crop)))
10488 {
10489 ssize_t crop_y = XFIXNUM (XCAR (crop));
10490 MagickCropImage (image_wand, crop_width, crop_height,
10491 crop_x, crop_y);
10492 }
10493 }
10494 }
10495 }
10496
10497 #ifndef DONT_CREATE_TRANSFORMED_IMAGEMAGICK_IMAGE
10498
10499
10500
10501
10502
10503
10504 value = image_spec_value (img->spec, QCrotation, NULL);
10505 if (FLOATP (value))
10506 {
10507 rotation = XFLOAT_DATA (value);
10508 status = MagickRotateImage (image_wand, bg_wand, rotation);
10509 if (status == MagickFalse)
10510 {
10511 image_error ("Imagemagick image rotate failed");
10512 imagemagick_error (image_wand);
10513 goto imagemagick_error;
10514 }
10515 }
10516 #endif
10517
10518
10519
10520
10521
10522 {
10523 MagickWand *new_wand;
10524 MagickSetImageBackgroundColor (image_wand, bg_wand);
10525 #ifdef HAVE_MAGICKMERGEIMAGELAYERS
10526 new_wand = MagickMergeImageLayers (image_wand, MergeLayer);
10527 #else
10528 new_wand = MagickFlattenImages (image_wand);
10529 #endif
10530 DestroyMagickWand (image_wand);
10531 image_wand = new_wand;
10532 }
10533
10534
10535
10536 image_height = MagickGetImageHeight (image_wand);
10537 image_width = MagickGetImageWidth (image_wand);
10538
10539 if (! (image_width <= INT_MAX && image_height <= INT_MAX
10540 && check_image_size (f, image_width, image_height)))
10541 {
10542 image_size_error ();
10543 goto imagemagick_error;
10544 }
10545
10546 width = image_width;
10547 height = image_height;
10548
10549
10550
10551
10552 init_color_table ();
10553
10554 #if defined (HAVE_MAGICKEXPORTIMAGEPIXELS) && \
10555 ! defined (HAVE_NS) && ! defined (HAVE_HAIKU)
10556 if (imagemagick_render_type != 0)
10557 {
10558
10559
10560
10561 void *dataptr;
10562 int imagedepth = 24;
10563 const char *exportdepth = imagedepth <= 8 ? "I" : "BGRP";
10564
10565 if (!image_create_x_image_and_pixmap (f, img, width, height, imagedepth,
10566 &ximg, 0))
10567 {
10568 #ifdef COLOR_TABLE_SUPPORT
10569 free_color_table ();
10570 #endif
10571 image_error ("Imagemagick X bitmap allocation failure");
10572 goto imagemagick_error;
10573 }
10574 dataptr = ximg->data;
10575
10576
10577
10578
10579
10580
10581
10582
10583
10584
10585
10586
10587
10588
10589
10590
10591
10592
10593
10594
10595 int pixelwidth = CharPixel;
10596 MagickExportImagePixels (image_wand, 0, 0, width, height,
10597 exportdepth, pixelwidth, dataptr);
10598 }
10599 else
10600 #endif
10601 {
10602 size_t image_height;
10603 double quantum_range = QuantumRange;
10604 MagickRealType color_scale = 65535.0 / quantum_range;
10605
10606 if (!image_create_x_image_and_pixmap (f, img, width, height, 0,
10607 &ximg, 0))
10608 {
10609 #ifdef COLOR_TABLE_SUPPORT
10610 free_color_table ();
10611 #endif
10612 image_error ("Imagemagick X bitmap allocation failure");
10613 goto imagemagick_error;
10614 }
10615
10616
10617
10618
10619
10620
10621 iterator = NewPixelIterator (image_wand);
10622 if (! iterator)
10623 {
10624 #ifdef COLOR_TABLE_SUPPORT
10625 free_color_table ();
10626 #endif
10627 image_destroy_x_image (ximg);
10628 image_error ("Imagemagick pixel iterator creation failed");
10629 goto imagemagick_error;
10630 }
10631
10632 image_height = MagickGetImageHeight (image_wand);
10633 for (y = 0; y < image_height; y++)
10634 {
10635 size_t row_width;
10636 pixels = PixelGetNextIteratorRow (iterator, &row_width);
10637 if (! pixels)
10638 break;
10639 int xlim = min (row_width, width);
10640 for (x = 0; x < xlim; x++)
10641 {
10642 PixelGetMagickColor (pixels[x], &pixel);
10643 PUT_PIXEL (ximg, x, y,
10644 lookup_rgb_color (f,
10645 color_scale * pixel.red,
10646 color_scale * pixel.green,
10647 color_scale * pixel.blue));
10648 }
10649 }
10650 DestroyPixelIterator (iterator);
10651 }
10652
10653 #ifdef COLOR_TABLE_SUPPORT
10654
10655 img->colors = colors_in_color_table (&img->ncolors);
10656 free_color_table ();
10657 #endif
10658
10659 img->width = width;
10660 img->height = height;
10661
10662
10663 image_put_x_image (f, img, ximg, 0);
10664
10665
10666 DestroyMagickWand (image_wand);
10667 if (bg_wand) DestroyPixelWand (bg_wand);
10668
10669
10670
10671
10672
10673
10674 return 1;
10675
10676 imagemagick_error:
10677 DestroyMagickWand (image_wand);
10678 if (bg_wand) DestroyPixelWand (bg_wand);
10679
10680
10681 image_error ("Error parsing IMAGEMAGICK image `%s'", img->spec);
10682 return 0;
10683 }
10684
10685
10686
10687
10688
10689
10690 static bool
10691 imagemagick_load (struct frame *f, struct image *img)
10692 {
10693 bool success_p = 0;
10694 Lisp_Object file_name;
10695
10696
10697 file_name = image_spec_value (img->spec, QCfile, NULL);
10698 if (STRINGP (file_name))
10699 {
10700 Lisp_Object file = image_find_image_file (file_name);
10701 if (!STRINGP (file))
10702 {
10703 image_error ("Cannot find image file `%s'", file_name);
10704 return 0;
10705 }
10706 file = ENCODE_FILE (file);
10707 #ifdef WINDOWSNT
10708 file = ansi_encode_filename (file);
10709 #endif
10710 success_p = imagemagick_load_image (f, img, 0, 0, SSDATA (file));
10711 }
10712
10713
10714 else
10715 {
10716 Lisp_Object data;
10717
10718 data = image_spec_value (img->spec, QCdata, NULL);
10719 if (!STRINGP (data))
10720 {
10721 image_error ("Invalid image data `%s'", data);
10722 return 0;
10723 }
10724 success_p = imagemagick_load_image (f, img, SDATA (data),
10725 SBYTES (data), NULL);
10726 }
10727
10728 return success_p;
10729 }
10730
10731 DEFUN ("imagemagick-types", Fimagemagick_types, Simagemagick_types, 0, 0, 0,
10732 doc:
10733
10734
10735
10736
10737
10738
10739
10740 )
10741 (void)
10742 {
10743 Lisp_Object typelist = Qnil;
10744 size_t numf = 0;
10745 ExceptionInfo *ex;
10746 char **imtypes;
10747 size_t i;
10748
10749 imagemagick_initialize ();
10750 ex = AcquireExceptionInfo ();
10751 imtypes = GetMagickList ("*", &numf, ex);
10752 DestroyExceptionInfo (ex);
10753
10754 for (i = 0; i < numf; i++)
10755 {
10756 Lisp_Object imagemagicktype = intern (imtypes[i]);
10757 typelist = Fcons (imagemagicktype, typelist);
10758 imtypes[i] = MagickRelinquishMemory (imtypes[i]);
10759 }
10760
10761 MagickRelinquishMemory (imtypes);
10762 return Fnreverse (typelist);
10763 }
10764
10765 #endif
10766
10767
10768
10769
10770
10771
10772
10773 #ifdef HAVE_RSVG
10774
10775
10776
10777 static bool svg_load_image (struct frame *, struct image *,
10778 char *, ptrdiff_t, char *);
10779
10780
10781
10782 enum svg_keyword_index
10783 {
10784 SVG_TYPE,
10785 SVG_DATA,
10786 SVG_FILE,
10787 SVG_BASE_URI,
10788 SVG_CSS,
10789 SVG_ASCENT,
10790 SVG_MARGIN,
10791 SVG_RELIEF,
10792 SVG_ALGORITHM,
10793 SVG_HEURISTIC_MASK,
10794 SVG_MASK,
10795 SVG_FOREGROUND,
10796 SVG_BACKGROUND,
10797 SVG_LAST
10798 };
10799
10800
10801
10802
10803 static const struct image_keyword svg_format[SVG_LAST] =
10804 {
10805 {":type", IMAGE_SYMBOL_VALUE, 1},
10806 {":data", IMAGE_STRING_VALUE, 0},
10807 {":file", IMAGE_STRING_VALUE, 0},
10808 {":base-uri", IMAGE_STRING_VALUE, 0},
10809 {":css", IMAGE_STRING_VALUE, 0},
10810 {":ascent", IMAGE_ASCENT_VALUE, 0},
10811 {":margin", IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR, 0},
10812 {":relief", IMAGE_INTEGER_VALUE, 0},
10813 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10814 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10815 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10816 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
10817 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
10818 };
10819
10820
10821
10822
10823
10824 static bool
10825 svg_image_p (Lisp_Object object)
10826 {
10827 struct image_keyword fmt[SVG_LAST];
10828 memcpy (fmt, svg_format, sizeof fmt);
10829
10830 if (!parse_image_spec (object, fmt, SVG_LAST, Qsvg))
10831 return 0;
10832
10833
10834 return fmt[SVG_FILE].count + fmt[SVG_DATA].count == 1;
10835 }
10836
10837
10838
10839
10840 # ifdef WINDOWSNT
10841 # if (__W32API_MAJOR_VERSION + (__W32API_MINOR_VERSION >= 18)) >= 4
10842 # define W32_SAVE_MINGW_VERSION __MINGW_MAJOR_VERSION
10843 # undef __MINGW_MAJOR_VERSION
10844 # define __MINGW_MAJOR_VERSION 4
10845 # endif
10846 # endif
10847
10848 # include <librsvg/rsvg.h>
10849
10850
10851 # ifndef LIBRSVG_CHECK_VERSION
10852 # define LIBRSVG_CHECK_VERSION(v, w, x) false
10853 # endif
10854
10855 # ifdef WINDOWSNT
10856
10857
10858 # if defined W32_SAVE_MINGW_VERSION && defined __MINGW_MAJOR_VERSION
10859 # undef __MINGW_MAJOR_VERSION
10860 # define __MINGW_MAJOR_VERSION W32_SAVE_MINGW_VERSION
10861 # ifdef __MINGW_MAJOR_VERSION
10862 # undef W32_SAVE_MINGW_VERSION
10863 # endif
10864 # endif
10865
10866
10867 # if LIBRSVG_CHECK_VERSION (2, 32, 0)
10868 DEF_DLL_FN (GFile *, g_file_new_for_path, (char const *));
10869 DEF_DLL_FN (GInputStream *, g_memory_input_stream_new_from_data,
10870 (void const *, gssize, GDestroyNotify));
10871 DEF_DLL_FN (RsvgHandle *, rsvg_handle_new_from_stream_sync,
10872 (GInputStream *, GFile *, RsvgHandleFlags, GCancellable *,
10873 GError **error));
10874 # else
10875 DEF_DLL_FN (RsvgHandle *, rsvg_handle_new, (void));
10876 DEF_DLL_FN (void, rsvg_handle_set_base_uri, (RsvgHandle *, const char *));
10877 DEF_DLL_FN (gboolean, rsvg_handle_write,
10878 (RsvgHandle *, const guchar *, gsize, GError **));
10879 DEF_DLL_FN (gboolean, rsvg_handle_close, (RsvgHandle *, GError **));
10880 # endif
10881
10882 DEF_DLL_FN (void, rsvg_handle_set_dpi_x_y,
10883 (RsvgHandle * handle, double dpi_x, double dpi_y));
10884
10885 # if LIBRSVG_CHECK_VERSION (2, 52, 1)
10886 DEF_DLL_FN (gboolean, rsvg_handle_get_intrinsic_size_in_pixels,
10887 (RsvgHandle *, gdouble *, gdouble *));
10888 # endif
10889 # if LIBRSVG_CHECK_VERSION (2, 46, 0)
10890 DEF_DLL_FN (void, rsvg_handle_get_intrinsic_dimensions,
10891 (RsvgHandle *, gboolean *, RsvgLength *, gboolean *,
10892 RsvgLength *, gboolean *, RsvgRectangle *));
10893 DEF_DLL_FN (gboolean, rsvg_handle_get_geometry_for_layer,
10894 (RsvgHandle *, const char *, const RsvgRectangle *,
10895 RsvgRectangle *, RsvgRectangle *, GError **));
10896 # else
10897 DEF_DLL_FN (void, rsvg_handle_get_dimensions,
10898 (RsvgHandle *, RsvgDimensionData *));
10899 # endif
10900
10901 # if LIBRSVG_CHECK_VERSION (2, 48, 0)
10902 DEF_DLL_FN (gboolean, rsvg_handle_set_stylesheet,
10903 (RsvgHandle *, const guint8 *, gsize, GError **));
10904 # endif
10905 DEF_DLL_FN (GdkPixbuf *, rsvg_handle_get_pixbuf, (RsvgHandle *));
10906 DEF_DLL_FN (int, gdk_pixbuf_get_width, (const GdkPixbuf *));
10907 DEF_DLL_FN (int, gdk_pixbuf_get_height, (const GdkPixbuf *));
10908 DEF_DLL_FN (guchar *, gdk_pixbuf_get_pixels, (const GdkPixbuf *));
10909 DEF_DLL_FN (int, gdk_pixbuf_get_rowstride, (const GdkPixbuf *));
10910 DEF_DLL_FN (GdkColorspace, gdk_pixbuf_get_colorspace, (const GdkPixbuf *));
10911 DEF_DLL_FN (int, gdk_pixbuf_get_n_channels, (const GdkPixbuf *));
10912 DEF_DLL_FN (gboolean, gdk_pixbuf_get_has_alpha, (const GdkPixbuf *));
10913 DEF_DLL_FN (int, gdk_pixbuf_get_bits_per_sample, (const GdkPixbuf *));
10914
10915 # if ! GLIB_CHECK_VERSION (2, 36, 0)
10916 DEF_DLL_FN (void, g_type_init, (void));
10917 # endif
10918 DEF_DLL_FN (void, g_object_unref, (gpointer));
10919 DEF_DLL_FN (void, g_error_free, (GError *));
10920
10921 static bool
10922 init_svg_functions (void)
10923 {
10924 HMODULE library, gdklib = NULL, glib = NULL, gobject = NULL, giolib = NULL;
10925
10926 if (!(glib = w32_delayed_load (Qglib))
10927 || !(gobject = w32_delayed_load (Qgobject))
10928 # if LIBRSVG_CHECK_VERSION (2, 32, 0)
10929 || !(giolib = w32_delayed_load (Qgio))
10930 # endif
10931 || !(gdklib = w32_delayed_load (Qgdk_pixbuf))
10932 || !(library = w32_delayed_load (Qsvg)))
10933 {
10934 if (gdklib) FreeLibrary (gdklib);
10935 if (giolib) FreeLibrary (giolib);
10936 if (gobject) FreeLibrary (gobject);
10937 if (glib) FreeLibrary (glib);
10938 return 0;
10939 }
10940
10941 #if LIBRSVG_CHECK_VERSION (2, 32, 0)
10942 LOAD_DLL_FN (giolib, g_file_new_for_path);
10943 LOAD_DLL_FN (giolib, g_memory_input_stream_new_from_data);
10944 LOAD_DLL_FN (library, rsvg_handle_new_from_stream_sync);
10945 #else
10946 LOAD_DLL_FN (library, rsvg_handle_new);
10947 LOAD_DLL_FN (library, rsvg_handle_set_base_uri);
10948 LOAD_DLL_FN (library, rsvg_handle_write);
10949 LOAD_DLL_FN (library, rsvg_handle_close);
10950 #endif
10951 LOAD_DLL_FN (library, rsvg_handle_set_dpi_x_y);
10952 #if LIBRSVG_CHECK_VERSION (2, 52, 1)
10953 LOAD_DLL_FN (library, rsvg_handle_get_intrinsic_size_in_pixels);
10954 #endif
10955 #if LIBRSVG_CHECK_VERSION (2, 46, 0)
10956 LOAD_DLL_FN (library, rsvg_handle_get_intrinsic_dimensions);
10957 LOAD_DLL_FN (library, rsvg_handle_get_geometry_for_layer);
10958 #else
10959 LOAD_DLL_FN (library, rsvg_handle_get_dimensions);
10960 #endif
10961 #if LIBRSVG_CHECK_VERSION (2, 48, 0)
10962 LOAD_DLL_FN (library, rsvg_handle_set_stylesheet);
10963 #endif
10964 LOAD_DLL_FN (library, rsvg_handle_get_pixbuf);
10965
10966 LOAD_DLL_FN (gdklib, gdk_pixbuf_get_width);
10967 LOAD_DLL_FN (gdklib, gdk_pixbuf_get_height);
10968 LOAD_DLL_FN (gdklib, gdk_pixbuf_get_pixels);
10969 LOAD_DLL_FN (gdklib, gdk_pixbuf_get_rowstride);
10970 LOAD_DLL_FN (gdklib, gdk_pixbuf_get_colorspace);
10971 LOAD_DLL_FN (gdklib, gdk_pixbuf_get_n_channels);
10972 LOAD_DLL_FN (gdklib, gdk_pixbuf_get_has_alpha);
10973 LOAD_DLL_FN (gdklib, gdk_pixbuf_get_bits_per_sample);
10974
10975 # if ! GLIB_CHECK_VERSION (2, 36, 0)
10976 LOAD_DLL_FN (gobject, g_type_init);
10977 # endif
10978 LOAD_DLL_FN (gobject, g_object_unref);
10979 LOAD_DLL_FN (glib, g_error_free);
10980
10981 return 1;
10982 }
10983
10984
10985
10986
10987 # undef gdk_pixbuf_get_bits_per_sample
10988 # undef gdk_pixbuf_get_colorspace
10989 # undef gdk_pixbuf_get_has_alpha
10990 # undef gdk_pixbuf_get_height
10991 # undef gdk_pixbuf_get_n_channels
10992 # undef gdk_pixbuf_get_pixels
10993 # undef gdk_pixbuf_get_rowstride
10994 # undef gdk_pixbuf_get_width
10995 # undef g_error_free
10996 # undef g_object_unref
10997 # undef g_type_init
10998 # if LIBRSVG_CHECK_VERSION (2, 52, 1)
10999 # undef rsvg_handle_get_intrinsic_size_in_pixels
11000 # endif
11001 # if LIBRSVG_CHECK_VERSION (2, 46, 0)
11002 # undef rsvg_handle_get_intrinsic_dimensions
11003 # undef rsvg_handle_get_geometry_for_layer
11004 # else
11005 # undef rsvg_handle_get_dimensions
11006 # endif
11007 # if LIBRSVG_CHECK_VERSION (2, 48, 0)
11008 # undef rsvg_handle_set_stylesheet
11009 # endif
11010 # undef rsvg_handle_get_pixbuf
11011 # if LIBRSVG_CHECK_VERSION (2, 32, 0)
11012 # undef g_file_new_for_path
11013 # undef g_memory_input_stream_new_from_data
11014 # undef rsvg_handle_new_from_stream_sync
11015 # else
11016 # undef rsvg_handle_close
11017 # undef rsvg_handle_new
11018 # undef rsvg_handle_set_base_uri
11019 # undef rsvg_handle_write
11020 # endif
11021 # undef rsvg_handle_set_dpi_x_y
11022
11023 # define gdk_pixbuf_get_bits_per_sample fn_gdk_pixbuf_get_bits_per_sample
11024 # define gdk_pixbuf_get_colorspace fn_gdk_pixbuf_get_colorspace
11025 # define gdk_pixbuf_get_has_alpha fn_gdk_pixbuf_get_has_alpha
11026 # define gdk_pixbuf_get_height fn_gdk_pixbuf_get_height
11027 # define gdk_pixbuf_get_n_channels fn_gdk_pixbuf_get_n_channels
11028 # define gdk_pixbuf_get_pixels fn_gdk_pixbuf_get_pixels
11029 # define gdk_pixbuf_get_rowstride fn_gdk_pixbuf_get_rowstride
11030 # define gdk_pixbuf_get_width fn_gdk_pixbuf_get_width
11031 # define g_error_free fn_g_error_free
11032 # define g_object_unref fn_g_object_unref
11033 # if ! GLIB_CHECK_VERSION (2, 36, 0)
11034 # define g_type_init fn_g_type_init
11035 # endif
11036 # if LIBRSVG_CHECK_VERSION (2, 52, 1)
11037 # define rsvg_handle_get_intrinsic_size_in_pixels \
11038 fn_rsvg_handle_get_intrinsic_size_in_pixels
11039 # endif
11040 # if LIBRSVG_CHECK_VERSION (2, 46, 0)
11041 # define rsvg_handle_get_intrinsic_dimensions \
11042 fn_rsvg_handle_get_intrinsic_dimensions
11043 # define rsvg_handle_get_geometry_for_layer \
11044 fn_rsvg_handle_get_geometry_for_layer
11045 # else
11046 # define rsvg_handle_get_dimensions fn_rsvg_handle_get_dimensions
11047 # endif
11048 # if LIBRSVG_CHECK_VERSION (2, 48, 0)
11049 # define rsvg_handle_set_stylesheet fn_rsvg_handle_set_stylesheet
11050 # endif
11051 # define rsvg_handle_get_pixbuf fn_rsvg_handle_get_pixbuf
11052 # if LIBRSVG_CHECK_VERSION (2, 32, 0)
11053 # define g_file_new_for_path fn_g_file_new_for_path
11054 # define g_memory_input_stream_new_from_data \
11055 fn_g_memory_input_stream_new_from_data
11056 # define rsvg_handle_new_from_stream_sync fn_rsvg_handle_new_from_stream_sync
11057 # else
11058 # define rsvg_handle_close fn_rsvg_handle_close
11059 # define rsvg_handle_new fn_rsvg_handle_new
11060 # define rsvg_handle_set_base_uri fn_rsvg_handle_set_base_uri
11061 # define rsvg_handle_write fn_rsvg_handle_write
11062 # endif
11063 # define rsvg_handle_set_dpi_x_y fn_rsvg_handle_set_dpi_x_y
11064
11065 # endif
11066
11067
11068
11069
11070 static bool
11071 svg_load (struct frame *f, struct image *img)
11072 {
11073 bool success_p = 0;
11074 Lisp_Object file_name, base_uri;
11075
11076
11077 file_name = image_spec_value (img->spec, QCfile, NULL);
11078 base_uri = image_spec_value (img->spec, QCbase_uri, NULL);
11079 if (STRINGP (file_name))
11080 {
11081 int fd;
11082 Lisp_Object file = image_find_image_fd (file_name, &fd);
11083 if (!STRINGP (file))
11084 {
11085 image_error ("Cannot find image file `%s'", file_name);
11086 return 0;
11087 }
11088
11089
11090 ptrdiff_t size;
11091 char *contents = slurp_file (fd, &size);
11092 if (contents == NULL)
11093 {
11094 image_error ("Error loading SVG image `%s'", file);
11095 return 0;
11096 }
11097
11098 if (!STRINGP (base_uri))
11099 base_uri = file;
11100 success_p = svg_load_image (f, img, contents, size,
11101 SSDATA (ENCODE_FILE (base_uri)));
11102 xfree (contents);
11103 }
11104
11105
11106 else
11107 {
11108 Lisp_Object data;
11109
11110 data = image_spec_value (img->spec, QCdata, NULL);
11111 if (!STRINGP (data))
11112 {
11113 image_error ("Invalid image data `%s'", data);
11114 return 0;
11115 }
11116 if (!STRINGP (base_uri))
11117 base_uri = BVAR (current_buffer, filename);
11118 success_p = svg_load_image (f, img, SSDATA (data), SBYTES (data),
11119 (STRINGP (base_uri) ?
11120 SSDATA (ENCODE_FILE (base_uri)) : NULL));
11121 }
11122
11123 return success_p;
11124 }
11125
11126 #if LIBRSVG_CHECK_VERSION (2, 46, 0)
11127 static double
11128 svg_css_length_to_pixels (RsvgLength length, double dpi, int font_size)
11129 {
11130 double value = length.length;
11131
11132 switch (length.unit)
11133 {
11134 case RSVG_UNIT_PX:
11135
11136 break;
11137 case RSVG_UNIT_CM:
11138
11139 value = dpi * value / 2.54;
11140 break;
11141 case RSVG_UNIT_MM:
11142
11143 value = dpi * value / 25.4;
11144 break;
11145 case RSVG_UNIT_PT:
11146
11147 value = dpi * value / 72;
11148 break;
11149 case RSVG_UNIT_PC:
11150
11151 value = dpi * value / 6;
11152 break;
11153 case RSVG_UNIT_IN:
11154 value *= dpi;
11155 break;
11156 #if LIBRSVG_CHECK_VERSION (2, 48, 0)
11157
11158
11159 case RSVG_UNIT_EM:
11160 value *= font_size;
11161 break;
11162 #endif
11163 default:
11164
11165
11166 value = 0;
11167 }
11168
11169 return value;
11170 }
11171 #endif
11172
11173
11174
11175
11176
11177
11178
11179
11180 static bool
11181 svg_load_image (struct frame *f, struct image *img, char *contents,
11182 ptrdiff_t size, char *filename)
11183 {
11184 RsvgHandle *rsvg_handle;
11185 double viewbox_width, viewbox_height;
11186 GError *err = NULL;
11187 GdkPixbuf *pixbuf;
11188 int width;
11189 int height;
11190 const guint8 *pixels;
11191 int rowstride;
11192 char *wrapped_contents = NULL;
11193 ptrdiff_t wrapped_size;
11194
11195 bool empty_errmsg = true;
11196 const char *errmsg = "";
11197 ptrdiff_t errlen = 0;
11198
11199 #if LIBRSVG_CHECK_VERSION (2, 48, 0)
11200 char *css = NULL;
11201 #endif
11202
11203 #if ! GLIB_CHECK_VERSION (2, 36, 0)
11204
11205
11206 g_type_init ();
11207 #endif
11208
11209
11210
11211 #if LIBRSVG_CHECK_VERSION (2, 32, 0)
11212 GInputStream *input_stream
11213 = g_memory_input_stream_new_from_data (contents, size, NULL);
11214 GFile *base_file = filename ? g_file_new_for_path (filename) : NULL;
11215 rsvg_handle = rsvg_handle_new_from_stream_sync (input_stream, base_file,
11216 RSVG_HANDLE_FLAGS_NONE,
11217 NULL, &err);
11218
11219 if (base_file)
11220 g_object_unref (base_file);
11221 g_object_unref (input_stream);
11222
11223
11224 if (!rsvg_handle || err) goto rsvg_error;
11225
11226 rsvg_handle_set_dpi_x_y (rsvg_handle, FRAME_DISPLAY_INFO (f)->resx,
11227 FRAME_DISPLAY_INFO (f)->resy);
11228
11229 #if LIBRSVG_CHECK_VERSION (2, 48, 0)
11230 Lisp_Object lcss = image_spec_value (img->spec, QCcss, NULL);
11231 if (!STRINGP (lcss))
11232 {
11233
11234
11235
11236
11237 const char *css_spec = "svg{font-family:\"%s\";font-size:%dpx}";
11238 int css_len = strlen (css_spec) + strlen (img->face_font_family) + 1;
11239 css = xmalloc (css_len);
11240 if (css_len <= snprintf (css, css_len, css_spec,
11241 img->face_font_family, img->face_font_size))
11242 goto rsvg_error;
11243
11244 rsvg_handle_set_stylesheet (rsvg_handle, (guint8 *)css, strlen (css), NULL);
11245 }
11246 else
11247 {
11248 css = xmalloc (SBYTES (lcss) + 1);
11249 strncpy (css, SSDATA (lcss), SBYTES (lcss));
11250 *(css + SBYTES (lcss) + 1) = 0;
11251 }
11252 #endif
11253
11254 #else
11255
11256 rsvg_handle = rsvg_handle_new ();
11257 eassume (rsvg_handle);
11258
11259 rsvg_handle_set_dpi_x_y (rsvg_handle, FRAME_DISPLAY_INFO (f)->resx,
11260 FRAME_DISPLAY_INFO (f)->resy);
11261
11262
11263
11264
11265
11266 if (filename)
11267 rsvg_handle_set_base_uri (rsvg_handle, filename);
11268
11269
11270 rsvg_handle_write (rsvg_handle, (unsigned char *) contents, size, &err);
11271 if (err) goto rsvg_error;
11272
11273
11274
11275 rsvg_handle_close (rsvg_handle, &err);
11276 if (err) goto rsvg_error;
11277 #endif
11278
11279
11280 #if LIBRSVG_CHECK_VERSION (2, 46, 0)
11281 gdouble gviewbox_width = 0, gviewbox_height = 0;
11282 gboolean has_viewbox = FALSE;
11283 # if LIBRSVG_CHECK_VERSION (2, 52, 1)
11284 has_viewbox = rsvg_handle_get_intrinsic_size_in_pixels (rsvg_handle,
11285 &gviewbox_width,
11286 &gviewbox_height);
11287 # endif
11288
11289 if (has_viewbox)
11290 {
11291 viewbox_width = gviewbox_width;
11292 viewbox_height = gviewbox_height;
11293 }
11294 else
11295 {
11296 RsvgRectangle zero_rect, viewbox, out_logical_rect;
11297
11298
11299 gboolean has_width, has_height;
11300 RsvgLength iwidth, iheight;
11301 double dpi = FRAME_DISPLAY_INFO (f)->resx;
11302
11303 rsvg_handle_get_intrinsic_dimensions (rsvg_handle,
11304 &has_width, &iwidth,
11305 &has_height, &iheight,
11306 &has_viewbox, &viewbox);
11307
11308 if (has_width && has_height)
11309 {
11310
11311 viewbox_width = svg_css_length_to_pixels (iwidth, dpi,
11312 img->face_font_size);
11313 viewbox_height = svg_css_length_to_pixels (iheight, dpi,
11314 img->face_font_size);
11315
11316
11317
11318 if (! (0 < viewbox_width) && (iwidth.unit == RSVG_UNIT_PERCENT))
11319 viewbox_width = (viewbox_height * viewbox.width / viewbox.height)
11320 * iwidth.length;
11321 else if (! (0 < viewbox_height) && (iheight.unit == RSVG_UNIT_PERCENT))
11322 viewbox_height = (viewbox_width * viewbox.height / viewbox.width)
11323 * iheight.length;
11324 }
11325 else if (has_width && has_viewbox)
11326 {
11327 viewbox_width = svg_css_length_to_pixels (iwidth, dpi,
11328 img->face_font_size);
11329 viewbox_height = viewbox_width * viewbox.height / viewbox.width;
11330 }
11331 else if (has_height && has_viewbox)
11332 {
11333 viewbox_height = svg_css_length_to_pixels (iheight, dpi,
11334 img->face_font_size);
11335 viewbox_width = viewbox_height * viewbox.width / viewbox.height;
11336 }
11337 else if (has_viewbox)
11338 {
11339 viewbox_width = viewbox.width;
11340 viewbox_height = viewbox.height;
11341 }
11342 else
11343 viewbox_width = viewbox_height = 0;
11344
11345 if (! (0 < viewbox_width && 0 < viewbox_height))
11346 {
11347
11348
11349 rsvg_handle_get_geometry_for_layer (rsvg_handle, NULL,
11350 &zero_rect, &viewbox,
11351 &out_logical_rect, NULL);
11352 viewbox_width = viewbox.x + viewbox.width;
11353 viewbox_height = viewbox.y + viewbox.height;
11354 }
11355 }
11356 #else
11357
11358 RsvgDimensionData dimension_data;
11359 rsvg_handle_get_dimensions (rsvg_handle, &dimension_data);
11360 viewbox_width = dimension_data.width;
11361 viewbox_height = dimension_data.height;
11362 #endif
11363
11364 #ifdef HAVE_NATIVE_TRANSFORMS
11365 compute_image_size (viewbox_width, viewbox_height, img,
11366 &width, &height);
11367
11368 width = scale_image_size (width, 1, FRAME_SCALE_FACTOR (f));
11369 height = scale_image_size (height, 1, FRAME_SCALE_FACTOR (f));
11370 #else
11371 width = viewbox_width;
11372 height = viewbox_height;
11373 #endif
11374
11375 if (! check_image_size (f, width, height))
11376 {
11377 image_size_error ();
11378 goto done_error;
11379 }
11380
11381
11382 g_object_unref (rsvg_handle);
11383
11384
11385
11386
11387 {
11388 Lisp_Object value;
11389 unsigned long foreground = img->face_foreground;
11390 unsigned long background = img->face_background;
11391
11392 Lisp_Object encoded_contents
11393 = Fbase64_encode_string (make_unibyte_string (contents, size), Qt);
11394
11395
11396
11397
11398
11399
11400
11401 const char *wrapper =
11402 "<svg xmlns:xlink=\"http://www.w3.org/1999/xlink\" "
11403 "xmlns:xi=\"http://www.w3.org/2001/XInclude\" "
11404 "style=\"color: #%06X; fill: currentColor;\" "
11405 "width=\"%d\" height=\"%d\" preserveAspectRatio=\"none\" "
11406 "viewBox=\"0 0 %f %f\">"
11407 "<rect width=\"100%%\" height=\"100%%\" fill=\"#%06X\"/>"
11408 "<xi:include href=\"data:image/svg+xml;base64,%s\"></xi:include>"
11409 "</svg>";
11410
11411
11412
11413 int buffer_size = SBYTES (encoded_contents) + strlen (wrapper) + 64;
11414
11415 value = image_spec_value (img->spec, QCforeground, NULL);
11416 if (!NILP (value))
11417 foreground = image_alloc_image_color (f, img, value, img->face_foreground);
11418 value = image_spec_value (img->spec, QCbackground, NULL);
11419 if (!NILP (value))
11420 {
11421 background = image_alloc_image_color (f, img, value, img->face_background);
11422 img->background = background;
11423 img->background_valid = 1;
11424 }
11425
11426 wrapped_contents = xmalloc (buffer_size);
11427
11428 if (buffer_size <= snprintf (wrapped_contents, buffer_size, wrapper,
11429 foreground & 0xFFFFFF, width, height,
11430 viewbox_width, viewbox_height,
11431 background & 0xFFFFFF,
11432 SSDATA (encoded_contents)))
11433 goto rsvg_error;
11434
11435 wrapped_size = strlen (wrapped_contents);
11436 }
11437
11438
11439
11440 #if LIBRSVG_CHECK_VERSION (2, 32, 0)
11441 input_stream = g_memory_input_stream_new_from_data (wrapped_contents, wrapped_size, NULL);
11442 base_file = filename ? g_file_new_for_path (filename) : NULL;
11443 rsvg_handle = rsvg_handle_new_from_stream_sync (input_stream, base_file,
11444 RSVG_HANDLE_FLAGS_NONE,
11445 NULL, &err);
11446
11447 if (base_file)
11448 g_object_unref (base_file);
11449 g_object_unref (input_stream);
11450
11451
11452 if (!rsvg_handle || err) goto rsvg_error;
11453
11454 rsvg_handle_set_dpi_x_y (rsvg_handle, FRAME_DISPLAY_INFO (f)->resx,
11455 FRAME_DISPLAY_INFO (f)->resy);
11456
11457 #if LIBRSVG_CHECK_VERSION (2, 48, 0)
11458 rsvg_handle_set_stylesheet (rsvg_handle, (guint8 *)css, strlen (css), NULL);
11459 #endif
11460 #else
11461
11462 rsvg_handle = rsvg_handle_new ();
11463 eassume (rsvg_handle);
11464
11465 rsvg_handle_set_dpi_x_y (rsvg_handle, FRAME_DISPLAY_INFO (f)->resx,
11466 FRAME_DISPLAY_INFO (f)->resy);
11467
11468
11469
11470
11471
11472 if (filename)
11473 rsvg_handle_set_base_uri (rsvg_handle, filename);
11474
11475
11476 rsvg_handle_write (rsvg_handle, (unsigned char *) wrapped_contents, wrapped_size, &err);
11477 if (err) goto rsvg_error;
11478
11479
11480
11481 rsvg_handle_close (rsvg_handle, &err);
11482 if (err) goto rsvg_error;
11483 #endif
11484
11485
11486
11487
11488 pixbuf = rsvg_handle_get_pixbuf (rsvg_handle);
11489 if (!pixbuf) goto rsvg_error;
11490 g_object_unref (rsvg_handle);
11491 xfree (wrapped_contents);
11492
11493 #if LIBRSVG_CHECK_VERSION (2, 48, 0)
11494 if (!STRINGP (lcss))
11495 xfree (css);
11496 #endif
11497
11498
11499 width = gdk_pixbuf_get_width (pixbuf);
11500 height = gdk_pixbuf_get_height (pixbuf);
11501 pixels = gdk_pixbuf_get_pixels (pixbuf);
11502 rowstride = gdk_pixbuf_get_rowstride (pixbuf);
11503
11504
11505 eassert (gdk_pixbuf_get_colorspace (pixbuf) == GDK_COLORSPACE_RGB);
11506 eassert (gdk_pixbuf_get_n_channels (pixbuf) == 4);
11507 eassert (gdk_pixbuf_get_has_alpha (pixbuf));
11508 eassert (gdk_pixbuf_get_bits_per_sample (pixbuf) == 8);
11509
11510 {
11511
11512 Emacs_Pix_Container ximg;
11513 if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, 0))
11514 {
11515 g_object_unref (pixbuf);
11516 return false;
11517 }
11518
11519 init_color_table ();
11520
11521
11522
11523
11524
11525 for (int y = 0; y < height; ++y)
11526 {
11527 for (int x = 0; x < width; ++x)
11528 {
11529 int red = *pixels++;
11530 int green = *pixels++;
11531 int blue = *pixels++;
11532
11533
11534 pixels++;
11535
11536 PUT_PIXEL (ximg, x, y, lookup_rgb_color (f, red << 8, green << 8, blue << 8));
11537 }
11538
11539 pixels += rowstride - 4 * width;
11540 }
11541
11542 #ifdef COLOR_TABLE_SUPPORT
11543
11544 img->colors = colors_in_color_table (&img->ncolors);
11545 free_color_table ();
11546 #endif
11547
11548 g_object_unref (pixbuf);
11549
11550 img->width = width;
11551 img->height = height;
11552
11553
11554
11555 IMAGE_BACKGROUND (img, f, (Emacs_Pix_Context)ximg);
11556
11557
11558 image_put_x_image (f, img, ximg, 0);
11559 }
11560
11561 eassume (err == NULL);
11562 return true;
11563
11564 rsvg_error:
11565 if (err && err->message[0])
11566 {
11567 errmsg = err->message;
11568 errlen = strlen (errmsg);
11569
11570
11571 while (errlen && c_isspace (errmsg[errlen - 1]))
11572 errlen--;
11573 empty_errmsg = errlen == 0;
11574 }
11575
11576 if (empty_errmsg)
11577 image_error ("Error parsing SVG image");
11578 else
11579 image_error ("Error parsing SVG image: %s", make_string (errmsg, errlen));
11580
11581 if (err)
11582 g_error_free (err);
11583
11584 done_error:
11585 if (rsvg_handle)
11586 g_object_unref (rsvg_handle);
11587 if (wrapped_contents)
11588 xfree (wrapped_contents);
11589 #if LIBRSVG_CHECK_VERSION (2, 48, 0)
11590 if (css && !STRINGP (lcss))
11591 xfree (css);
11592 #endif
11593 return false;
11594 }
11595
11596 #endif
11597
11598
11599
11600
11601
11602
11603
11604
11605 #if defined HAVE_X_WINDOWS && !defined USE_CAIRO
11606 #define HAVE_GHOSTSCRIPT 1
11607 #endif
11608
11609 #ifdef HAVE_GHOSTSCRIPT
11610
11611
11612
11613 enum gs_keyword_index
11614 {
11615 GS_TYPE,
11616 GS_PT_WIDTH,
11617 GS_PT_HEIGHT,
11618 GS_FILE,
11619 GS_LOADER,
11620 GS_BOUNDING_BOX,
11621 GS_ASCENT,
11622 GS_MARGIN,
11623 GS_RELIEF,
11624 GS_ALGORITHM,
11625 GS_HEURISTIC_MASK,
11626 GS_MASK,
11627 GS_BACKGROUND,
11628 GS_LAST
11629 };
11630
11631
11632
11633
11634 static const struct image_keyword gs_format[GS_LAST] =
11635 {
11636 {":type", IMAGE_SYMBOL_VALUE, 1},
11637 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
11638 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
11639 {":file", IMAGE_STRING_VALUE, 1},
11640 {":loader", IMAGE_FUNCTION_VALUE, 0},
11641 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
11642 {":ascent", IMAGE_ASCENT_VALUE, 0},
11643 {":margin", IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR, 0},
11644 {":relief", IMAGE_INTEGER_VALUE, 0},
11645 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11646 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11647 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11648 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
11649 };
11650
11651
11652
11653
11654 static bool
11655 gs_image_p (Lisp_Object object)
11656 {
11657 struct image_keyword fmt[GS_LAST];
11658 Lisp_Object tem;
11659 int i;
11660
11661 memcpy (fmt, gs_format, sizeof fmt);
11662
11663 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript))
11664 return 0;
11665
11666
11667 tem = fmt[GS_BOUNDING_BOX].value;
11668 if (CONSP (tem))
11669 {
11670 for (i = 0; i < 4; ++i, tem = XCDR (tem))
11671 if (!CONSP (tem) || !FIXNUMP (XCAR (tem)))
11672 return 0;
11673 if (!NILP (tem))
11674 return 0;
11675 }
11676 else if (VECTORP (tem))
11677 {
11678 if (ASIZE (tem) != 4)
11679 return 0;
11680 for (i = 0; i < 4; ++i)
11681 if (!FIXNUMP (AREF (tem, i)))
11682 return 0;
11683 }
11684 else
11685 return 0;
11686
11687 return 1;
11688 }
11689
11690
11691
11692
11693
11694 static bool
11695 gs_load (struct frame *f, struct image *img)
11696 {
11697 uintmax_t printnum1, printnum2;
11698 char buffer[sizeof " " + 2 * INT_STRLEN_BOUND (intmax_t)];
11699 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
11700 Lisp_Object frame;
11701 double in_width, in_height;
11702 Lisp_Object pixel_colors = Qnil;
11703
11704
11705
11706
11707
11708 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
11709 in_width = FIXNUMP (pt_width) ? XFIXNAT (pt_width) / 72.0 : 0;
11710 in_width *= FRAME_RES_X (f);
11711 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
11712 in_height = FIXNUMP (pt_height) ? XFIXNAT (pt_height) / 72.0 : 0;
11713 in_height *= FRAME_RES_Y (f);
11714
11715 if (! (in_width <= INT_MAX && in_height <= INT_MAX
11716 && check_image_size (f, in_width, in_height)))
11717 {
11718 image_size_error ();
11719 return 0;
11720 }
11721 img->width = in_width;
11722 img->height = in_height;
11723
11724
11725 eassert (img->pixmap == NO_PIXMAP);
11726
11727 if (image_check_image_size (0, img->width, img->height))
11728 {
11729
11730 block_input ();
11731 img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f),
11732 img->width, img->height,
11733 FRAME_DISPLAY_INFO (f)->n_planes);
11734 unblock_input ();
11735 }
11736
11737 if (!img->pixmap)
11738 {
11739 image_error ("Unable to create pixmap for `%s'" , img->spec);
11740 return 0;
11741 }
11742
11743
11744
11745
11746
11747 printnum1 = FRAME_X_DRAWABLE (f);
11748 printnum2 = img->pixmap;
11749 window_and_pixmap_id
11750 = make_formatted_string (buffer, "%"PRIuMAX" %"PRIuMAX,
11751 printnum1, printnum2);
11752
11753 printnum1 = FRAME_FOREGROUND_PIXEL (f);
11754 printnum2 = FRAME_BACKGROUND_PIXEL (f);
11755 pixel_colors
11756 = make_formatted_string (buffer, "%"PRIuMAX" %"PRIuMAX,
11757 printnum1, printnum2);
11758
11759 XSETFRAME (frame, f);
11760 loader = image_spec_value (img->spec, QCloader, NULL);
11761 if (NILP (loader))
11762 loader = intern ("gs-load-image");
11763
11764 img->lisp_data = call6 (loader, frame, img->spec,
11765 make_fixnum (img->width),
11766 make_fixnum (img->height),
11767 window_and_pixmap_id,
11768 pixel_colors);
11769 return PROCESSP (img->lisp_data);
11770 }
11771
11772
11773
11774
11775
11776
11777 void
11778 x_kill_gs_process (Pixmap pixmap, struct frame *f)
11779 {
11780 struct image_cache *c = FRAME_IMAGE_CACHE (f);
11781 ptrdiff_t i;
11782 struct image *img;
11783
11784
11785 for (i = 0; i < c->used; ++i)
11786 if (c->images[i]->pixmap == pixmap)
11787 break;
11788
11789
11790
11791 if (i == c->used)
11792 return;
11793
11794
11795
11796 img = c->images[i];
11797 eassert (PROCESSP (img->lisp_data));
11798 Fkill_process (img->lisp_data, Qnil);
11799 img->lisp_data = Qnil;
11800
11801 #if defined (HAVE_X_WINDOWS)
11802
11803
11804
11805
11806 if (x_mutable_colormap (FRAME_X_VISUAL_INFO (f)))
11807 {
11808 XImage *ximg;
11809
11810 block_input ();
11811
11812
11813 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
11814 0, 0, img->width, img->height, ~0, ZPixmap);
11815 if (ximg)
11816 {
11817
11818 init_color_table ();
11819
11820
11821
11822
11823 #ifdef COLOR_TABLE_SUPPORT
11824 for (int y = 0; y < img->height; ++y)
11825 for (int x = 0; x < img->width; ++x)
11826 {
11827 unsigned long pixel = XGetPixel (ximg, x, y);
11828
11829 lookup_pixel_color (f, pixel);
11830 }
11831
11832
11833 img->colors = colors_in_color_table (&img->ncolors);
11834 free_color_table ();
11835 #endif
11836 XDestroyImage (ximg);
11837 }
11838 else
11839 image_error ("Cannot get X image of `%s'; colors will not be freed",
11840 img->spec);
11841
11842 unblock_input ();
11843 }
11844 #endif
11845
11846
11847
11848 block_input ();
11849 postprocess_image (f, img);
11850 unblock_input ();
11851 }
11852
11853 #endif
11854
11855
11856
11857
11858
11859 DEFUN ("imagep", Fimagep, Simagep, 1, 1, 0,
11860 doc: )
11861 (Lisp_Object spec)
11862 {
11863 return valid_image_p (spec) ? Qt : Qnil;
11864 }
11865
11866 #ifdef GLYPH_DEBUG
11867
11868 DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0,
11869 doc: )
11870 (Lisp_Object spec)
11871 {
11872 ptrdiff_t id = -1;
11873
11874 if (valid_image_p (spec))
11875 id = lookup_image (SELECTED_FRAME (), spec, -1);
11876
11877 debug_print (spec);
11878 return make_fixnum (id);
11879 }
11880
11881 #endif
11882
11883
11884
11885
11886
11887
11888 DEFUN ("image-transforms-p", Fimage_transforms_p, Simage_transforms_p, 0, 1, 0,
11889 doc:
11890
11891
11892
11893
11894
11895
11896 )
11897 (Lisp_Object frame)
11898 {
11899 struct frame *f = decode_live_frame (frame);
11900 if (FRAME_WINDOW_P (f))
11901 {
11902 #ifdef HAVE_NATIVE_TRANSFORMS
11903 # if defined HAVE_IMAGEMAGICK || defined (USE_CAIRO) || defined (HAVE_NS) \
11904 || defined (HAVE_HAIKU)
11905 return list2 (Qscale, Qrotate90);
11906 # elif defined (HAVE_X_WINDOWS) && defined (HAVE_XRENDER)
11907 if (FRAME_DISPLAY_INFO (f)->xrender_supported_p)
11908 return list2 (Qscale, Qrotate90);
11909 # elif defined (HAVE_NTGUI)
11910 return (w32_image_rotations_p ()
11911 ? list2 (Qscale, Qrotate90)
11912 : list1 (Qscale));
11913 # endif
11914 #endif
11915 }
11916
11917 return Qnil;
11918 }
11919
11920 DEFUN ("image-cache-size", Fimage_cache_size, Simage_cache_size, 0, 0, 0,
11921 doc: )
11922 (void)
11923 {
11924 Lisp_Object tail, frame;
11925 size_t total = 0;
11926
11927 FOR_EACH_FRAME (tail, frame)
11928 if (FRAME_WINDOW_P (XFRAME (frame)))
11929 total += image_frame_cache_size (XFRAME (frame));
11930
11931 #if defined (HAVE_WEBP) || defined (HAVE_GIF)
11932 struct anim_cache *pcache = anim_cache;
11933 while (pcache)
11934 {
11935 total += pcache->byte_size;
11936 pcache = pcache->next;
11937 }
11938 #endif
11939
11940 return make_int (total);
11941 }
11942
11943
11944 DEFUN ("init-image-library", Finit_image_library, Sinit_image_library, 1, 1, 0,
11945 doc:
11946
11947
11948
11949
11950 )
11951 (Lisp_Object type)
11952 {
11953 return lookup_image_type (type) ? Qt : Qnil;
11954 }
11955
11956 static bool
11957 initialize_image_type (struct image_type const *type)
11958 {
11959 #ifdef WINDOWSNT
11960 Lisp_Object typesym = builtin_lisp_symbol (type->type);
11961
11962 # if HAVE_NATIVE_IMAGE_API
11963 if (image_can_use_native_api (typesym))
11964 return true;
11965 # endif
11966
11967 Lisp_Object tested = Fassq (typesym, Vlibrary_cache);
11968
11969 if (CONSP (tested))
11970 return !NILP (XCDR (tested)) ? true : false;
11971
11972 bool (*init) (void) = type->init;
11973 if (init)
11974 {
11975 bool type_valid = init ();
11976 Vlibrary_cache = Fcons (Fcons (typesym, type_valid ? Qt : Qnil),
11977 Vlibrary_cache);
11978 return type_valid;
11979 }
11980 #endif
11981 return true;
11982 }
11983
11984
11985
11986 static struct image_type const image_types[] =
11987 {
11988 #ifdef HAVE_GHOSTSCRIPT
11989 { SYMBOL_INDEX (Qpostscript), gs_image_p, gs_load, image_clear_image },
11990 #endif
11991 #ifdef HAVE_IMAGEMAGICK
11992 { SYMBOL_INDEX (Qimagemagick), imagemagick_image_p, imagemagick_load,
11993 imagemagick_clear_image },
11994 #endif
11995 #ifdef HAVE_RSVG
11996 { SYMBOL_INDEX (Qsvg), svg_image_p, svg_load, image_clear_image,
11997 IMAGE_TYPE_INIT (init_svg_functions) },
11998 #endif
11999 #if defined HAVE_PNG
12000 { SYMBOL_INDEX (Qpng), png_image_p, png_load, image_clear_image,
12001 IMAGE_TYPE_INIT (init_png_functions) },
12002 #endif
12003 #if defined HAVE_GIF
12004 { SYMBOL_INDEX (Qgif), gif_image_p, gif_load, gif_clear_image,
12005 IMAGE_TYPE_INIT (init_gif_functions) },
12006 #endif
12007 #if defined HAVE_TIFF
12008 { SYMBOL_INDEX (Qtiff), tiff_image_p, tiff_load, image_clear_image,
12009 IMAGE_TYPE_INIT (init_tiff_functions) },
12010 #endif
12011 #if defined HAVE_JPEG
12012 { SYMBOL_INDEX (Qjpeg), jpeg_image_p, jpeg_load, image_clear_image,
12013 IMAGE_TYPE_INIT (init_jpeg_functions) },
12014 #endif
12015 #if defined HAVE_XPM || defined HAVE_NS || defined HAVE_HAIKU || defined HAVE_PGTK
12016 { SYMBOL_INDEX (Qxpm), xpm_image_p, xpm_load, image_clear_image,
12017 IMAGE_TYPE_INIT (init_xpm_functions) },
12018 #endif
12019 #if defined HAVE_WEBP
12020 { SYMBOL_INDEX (Qwebp), webp_image_p, webp_load, image_clear_image,
12021 IMAGE_TYPE_INIT (init_webp_functions) },
12022 #endif
12023 { SYMBOL_INDEX (Qxbm), xbm_image_p, xbm_load, image_clear_image },
12024 { SYMBOL_INDEX (Qpbm), pbm_image_p, pbm_load, image_clear_image },
12025 };
12026
12027 #if HAVE_NATIVE_IMAGE_API
12028 struct image_type native_image_type =
12029 { SYMBOL_INDEX (Qnative_image), native_image_p, native_image_load,
12030 image_clear_image };
12031 #endif
12032
12033
12034
12035
12036 static struct image_type const *
12037 lookup_image_type (Lisp_Object type)
12038 {
12039 #if HAVE_NATIVE_IMAGE_API
12040 if (image_can_use_native_api (type))
12041 return &native_image_type;
12042 #endif
12043
12044 for (int i = 0; i < ARRAYELTS (image_types); i++)
12045 {
12046 struct image_type const *r = &image_types[i];
12047 if (EQ (type, builtin_lisp_symbol (r->type)))
12048 return initialize_image_type (r) ? r : NULL;
12049 }
12050 return NULL;
12051 }
12052
12053
12054
12055 void
12056 image_prune_animation_caches (bool clear)
12057 {
12058 #if defined (HAVE_WEBP) || defined (HAVE_GIF)
12059 anim_prune_animation_cache (clear? Qt: Qnil);
12060 #endif
12061 #ifdef HAVE_IMAGEMAGICK
12062 imagemagick_prune_animation_cache (clear);
12063 #endif
12064 }
12065
12066 void
12067 syms_of_image (void)
12068 {
12069
12070
12071 DEFVAR_LISP ("image-types", Vimage_types,
12072 doc:
12073
12074 );
12075 Vimage_types = Qnil;
12076
12077 DEFVAR_LISP ("max-image-size", Vmax_image_size,
12078 doc:
12079
12080
12081
12082
12083
12084
12085
12086 );
12087 Vmax_image_size = make_float (MAX_IMAGE_SIZE);
12088
12089
12090 DEFSYM (Qcount, "count");
12091 DEFSYM (Qextension_data, "extension-data");
12092 DEFSYM (Qdelay, "delay");
12093
12094
12095 DEFSYM (QCascent, ":ascent");
12096 DEFSYM (QCmargin, ":margin");
12097 DEFSYM (QCrelief, ":relief");
12098 DEFSYM (QCconversion, ":conversion");
12099 DEFSYM (QCcolor_symbols, ":color-symbols");
12100 DEFSYM (QCheuristic_mask, ":heuristic-mask");
12101 DEFSYM (QCindex, ":index");
12102 DEFSYM (QCcrop, ":crop");
12103 DEFSYM (QCrotation, ":rotation");
12104 DEFSYM (QCmatrix, ":matrix");
12105 DEFSYM (QCscale, ":scale");
12106 DEFSYM (QCtransform_smoothing, ":transform-smoothing");
12107 DEFSYM (QCcolor_adjustment, ":color-adjustment");
12108 DEFSYM (QCmask, ":mask");
12109 DEFSYM (QCflip, ":flip");
12110
12111
12112 DEFSYM (Qlaplace, "laplace");
12113 DEFSYM (Qemboss, "emboss");
12114 DEFSYM (Qedge_detection, "edge-detection");
12115 DEFSYM (Qheuristic, "heuristic");
12116
12117 DEFSYM (Qpostscript, "postscript");
12118 DEFSYM (QCmax_width, ":max-width");
12119 DEFSYM (QCmax_height, ":max-height");
12120
12121 DEFSYM (Qem, "em");
12122
12123 #ifdef HAVE_NATIVE_TRANSFORMS
12124 DEFSYM (Qscale, "scale");
12125 DEFSYM (Qrotate, "rotate");
12126 DEFSYM (Qrotate90, "rotate90");
12127 DEFSYM (Qcrop, "crop");
12128 #endif
12129
12130 #ifdef HAVE_GHOSTSCRIPT
12131 add_image_type (Qpostscript);
12132 DEFSYM (QCloader, ":loader");
12133 DEFSYM (QCpt_width, ":pt-width");
12134 DEFSYM (QCpt_height, ":pt-height");
12135 #endif
12136
12137 #ifdef HAVE_NTGUI
12138
12139
12140
12141
12142 DEFSYM (Qlibpng_version, "libpng-version");
12143 Fset (Qlibpng_version,
12144 #if HAVE_PNG
12145 make_fixnum (PNG_LIBPNG_VER)
12146 #else
12147 make_fixnum (-1)
12148 #endif
12149 );
12150 DEFSYM (Qlibgif_version, "libgif-version");
12151 Fset (Qlibgif_version,
12152 #ifdef HAVE_GIF
12153 make_fixnum (GIFLIB_MAJOR * 10000
12154 + GIFLIB_MINOR * 100
12155 + GIFLIB_RELEASE)
12156 #else
12157 make_fixnum (-1)
12158 #endif
12159 );
12160 DEFSYM (Qlibjpeg_version, "libjpeg-version");
12161 Fset (Qlibjpeg_version,
12162 #if HAVE_JPEG
12163 make_fixnum (JPEG_LIB_VERSION)
12164 #else
12165 make_fixnum (-1)
12166 #endif
12167 );
12168 #endif
12169
12170 DEFSYM (Qpbm, "pbm");
12171 add_image_type (Qpbm);
12172
12173 DEFSYM (Qxbm, "xbm");
12174 add_image_type (Qxbm);
12175
12176 #if defined (HAVE_XPM) || defined (HAVE_NS) \
12177 || defined (HAVE_HAIKU) || defined (HAVE_PGTK)
12178 DEFSYM (Qxpm, "xpm");
12179 add_image_type (Qxpm);
12180 #endif
12181
12182 #if defined (HAVE_JPEG) || defined (HAVE_NATIVE_IMAGE_API)
12183 DEFSYM (Qjpeg, "jpeg");
12184 add_image_type (Qjpeg);
12185 #endif
12186
12187 #if defined (HAVE_TIFF) || defined (HAVE_NATIVE_IMAGE_API)
12188 DEFSYM (Qtiff, "tiff");
12189 add_image_type (Qtiff);
12190 #endif
12191
12192 #if defined (HAVE_GIF) || defined (HAVE_NATIVE_IMAGE_API)
12193 DEFSYM (Qgif, "gif");
12194 add_image_type (Qgif);
12195 #endif
12196
12197 #if defined (HAVE_PNG) || defined (HAVE_NATIVE_IMAGE_API)
12198 DEFSYM (Qpng, "png");
12199 add_image_type (Qpng);
12200 #endif
12201
12202 #if defined (HAVE_WEBP) || (defined (HAVE_NATIVE_IMAGE_API) \
12203 && defined (HAVE_HAIKU))
12204 DEFSYM (Qwebp, "webp");
12205 DEFSYM (Qwebpdemux, "webpdemux");
12206 add_image_type (Qwebp);
12207 #endif
12208
12209 #if defined (HAVE_IMAGEMAGICK)
12210 DEFSYM (Qimagemagick, "imagemagick");
12211 add_image_type (Qimagemagick);
12212 #endif
12213
12214 #if defined (HAVE_RSVG)
12215 DEFSYM (Qsvg, "svg");
12216 DEFSYM (QCbase_uri, ":base-uri");
12217 DEFSYM (QCcss, ":css");
12218 add_image_type (Qsvg);
12219 #ifdef HAVE_NTGUI
12220
12221 DEFSYM (Qgdk_pixbuf, "gdk-pixbuf");
12222 DEFSYM (Qglib, "glib");
12223 # if LIBRSVG_CHECK_VERSION (2, 32, 0)
12224 DEFSYM (Qgio, "gio");
12225 # endif
12226 DEFSYM (Qgobject, "gobject");
12227 #endif
12228 #elif defined HAVE_NATIVE_IMAGE_API \
12229 && ((defined HAVE_NS && defined NS_IMPL_COCOA) \
12230 || defined HAVE_HAIKU)
12231 DEFSYM (Qsvg, "svg");
12232
12233
12234 if (image_can_use_native_api (Qsvg))
12235 add_image_type (Qsvg);
12236 #endif
12237
12238 #ifdef HAVE_NS
12239 DEFSYM (Qheic, "heic");
12240 add_image_type (Qheic);
12241 #endif
12242
12243 #if HAVE_NATIVE_IMAGE_API
12244 DEFSYM (Qnative_image, "native-image");
12245
12246 # if defined HAVE_NTGUI || defined HAVE_HAIKU
12247 DEFSYM (Qbmp, "bmp");
12248 add_image_type (Qbmp);
12249 # endif
12250
12251 # ifdef HAVE_NTGUI
12252 DEFSYM (Qgdiplus, "gdiplus");
12253 DEFSYM (Qshlwapi, "shlwapi");
12254 # endif
12255 #endif
12256
12257 defsubr (&Sinit_image_library);
12258 #ifdef HAVE_IMAGEMAGICK
12259 defsubr (&Simagemagick_types);
12260 #endif
12261 defsubr (&Sclear_image_cache);
12262 defsubr (&Simage_flush);
12263 defsubr (&Simage_size);
12264 defsubr (&Simage_mask_p);
12265 defsubr (&Simage_metadata);
12266 defsubr (&Simage_cache_size);
12267 defsubr (&Simagep);
12268
12269 #ifdef GLYPH_DEBUG
12270 defsubr (&Slookup_image);
12271 #endif
12272
12273 DEFSYM (QCanimate_buffer, ":animate-buffer");
12274 DEFSYM (QCanimate_tardiness, ":animate-tardiness");
12275 DEFSYM (QCanimate_position, ":animate-position");
12276 DEFSYM (QCanimate_multi_frame_data, ":animate-multi-frame-data");
12277
12278 defsubr (&Simage_transforms_p);
12279
12280 DEFVAR_BOOL ("cross-disabled-images", cross_disabled_images,
12281 doc:
12282
12283 );
12284 cross_disabled_images = 0;
12285
12286 DEFVAR_LISP ("x-bitmap-file-path", Vx_bitmap_file_path,
12287 doc: );
12288 Vx_bitmap_file_path = decode_env_path (0, PATH_BITMAPS, 0);
12289
12290 DEFVAR_LISP ("image-cache-eviction-delay", Vimage_cache_eviction_delay,
12291 doc:
12292
12293
12294
12295
12296
12297 );
12298 Vimage_cache_eviction_delay = make_fixnum (300);
12299 #ifdef HAVE_IMAGEMAGICK
12300 DEFVAR_INT ("imagemagick-render-type", imagemagick_render_type,
12301 doc:
12302
12303
12304
12305
12306
12307
12308 );
12309
12310 imagemagick_render_type = 0;
12311 #endif
12312 }