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