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 Lisp_Object specified_bg
8216 = image_spec_value (img->spec, QCbackground, NULL);
8217 Emacs_Color color;
8218
8219
8220
8221
8222 if (STRINGP (specified_bg)
8223 ? FRAME_TERMINAL (f)->defined_color_hook (f,
8224 SSDATA (specified_bg),
8225 &color,
8226 false,
8227 false)
8228 : (FRAME_TERMINAL (f)->query_frame_background_color (f, &color),
8229 true))
8230
8231 {
8232 int shift = bit_depth == 16 ? 0 : 8;
8233 png_color_16 bg = { 0 };
8234 bg.red = color.red >> shift;
8235 bg.green = color.green >> shift;
8236 bg.blue = color.blue >> shift;
8237
8238 png_set_background (png_ptr, &bg,
8239 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
8240 }
8241 }
8242
8243 png_set_interlace_handling (png_ptr);
8244 png_read_update_info (png_ptr, info_ptr);
8245
8246
8247
8248
8249
8250
8251 channels = png_get_channels (png_ptr, info_ptr);
8252 eassert (channels == 3 || channels == 4);
8253
8254
8255 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
8256
8257
8258 if (ckd_mul (&nbytes, row_bytes, sizeof *pixels)
8259 || ckd_mul (&nbytes, nbytes, height))
8260 memory_full (SIZE_MAX);
8261 c->pixels = pixels = xmalloc (nbytes);
8262 c->rows = rows = xmalloc (height * sizeof *rows);
8263 for (i = 0; i < height; ++i)
8264 rows[i] = pixels + i * row_bytes;
8265
8266
8267 png_read_image (png_ptr, rows);
8268 png_read_end (png_ptr, info_ptr);
8269 if (fp)
8270 {
8271 emacs_fclose (fp);
8272 c->fp = NULL;
8273 }
8274
8275
8276
8277 if (channels == 4
8278 && transparent_p
8279 && !image_create_x_image_and_pixmap (f, img, width, height, 1,
8280 &mask_img, 1))
8281 {
8282 image_destroy_x_image (ximg);
8283 image_clear_image_1 (f, img, CLEAR_IMAGE_PIXMAP);
8284 goto error;
8285 }
8286
8287
8288 init_color_table ();
8289
8290 for (y = 0; y < height; ++y)
8291 {
8292 png_byte *p = rows[y];
8293
8294 for (x = 0; x < width; ++x)
8295 {
8296 int r, g, b;
8297
8298 r = *p++ << 8;
8299 g = *p++ << 8;
8300 b = *p++ << 8;
8301 PUT_PIXEL (ximg, x, y, lookup_rgb_color (f, r, g, b));
8302
8303
8304
8305
8306
8307
8308
8309
8310
8311
8312
8313
8314
8315
8316
8317
8318 if (channels == 4)
8319 {
8320 if (mask_img)
8321 PUT_PIXEL (mask_img, x, y, *p > 0 ? PIX_MASK_DRAW : PIX_MASK_RETAIN);
8322 ++p;
8323 }
8324 }
8325 }
8326
8327 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
8328
8329
8330 {
8331 png_color_16 *bg;
8332 if (png_get_bKGD (png_ptr, info_ptr, &bg))
8333 {
8334 #ifndef USE_CAIRO
8335 img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue);
8336 #else
8337 char color_name[30];
8338 sprintf (color_name, "#%04x%04x%04x", bg->red, bg->green, bg->blue);
8339 img->background
8340 = image_alloc_image_color (f, img, build_string (color_name), 0);
8341 #endif
8342 img->background_valid = 1;
8343 }
8344 }
8345
8346 # ifdef COLOR_TABLE_SUPPORT
8347
8348 img->colors = colors_in_color_table (&img->ncolors);
8349 free_color_table ();
8350 # endif
8351
8352
8353 png_destroy_read_struct (&c->png_ptr, &c->info_ptr, &c->end_info);
8354 xfree (rows);
8355 xfree (pixels);
8356
8357 img->width = width;
8358 img->height = height;
8359
8360
8361
8362 IMAGE_BACKGROUND (img, f, (Emacs_Pix_Context)ximg);
8363
8364
8365 image_put_x_image (f, img, ximg, 0);
8366
8367
8368 if (mask_img)
8369 {
8370
8371
8372 image_background_transparent (img, f, (Emacs_Pix_Context)mask_img);
8373
8374 image_put_x_image (f, img, mask_img, 1);
8375 }
8376
8377 return 1;
8378 }
8379
8380 static bool
8381 png_load (struct frame *f, struct image *img)
8382 {
8383 struct png_load_context c;
8384 return png_load_body (f, img, &c);
8385 }
8386
8387 #endif
8388
8389
8390
8391
8392
8393
8394
8395 #if defined (HAVE_JPEG)
8396
8397
8398
8399 enum jpeg_keyword_index
8400 {
8401 JPEG_TYPE,
8402 JPEG_DATA,
8403 JPEG_FILE,
8404 JPEG_ASCENT,
8405 JPEG_MARGIN,
8406 JPEG_RELIEF,
8407 JPEG_ALGORITHM,
8408 JPEG_HEURISTIC_MASK,
8409 JPEG_MASK,
8410 JPEG_BACKGROUND,
8411 JPEG_LAST
8412 };
8413
8414
8415
8416
8417 static const struct image_keyword jpeg_format[JPEG_LAST] =
8418 {
8419 {":type", IMAGE_SYMBOL_VALUE, 1},
8420 {":data", IMAGE_STRING_VALUE, 0},
8421 {":file", IMAGE_STRING_VALUE, 0},
8422 {":ascent", IMAGE_ASCENT_VALUE, 0},
8423 {":margin", IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR, 0},
8424 {":relief", IMAGE_INTEGER_VALUE, 0},
8425 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8426 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8427 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8428 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
8429 };
8430
8431
8432
8433 static bool
8434 jpeg_image_p (Lisp_Object object)
8435 {
8436 struct image_keyword fmt[JPEG_LAST];
8437
8438 memcpy (fmt, jpeg_format, sizeof fmt);
8439
8440 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg))
8441 return 0;
8442
8443
8444 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
8445 }
8446
8447 #endif
8448
8449 #ifdef HAVE_JPEG
8450
8451
8452
8453 # ifdef HAVE_STDLIB_H
8454 # undef HAVE_STDLIB_H
8455 # endif
8456
8457 # if defined (HAVE_NTGUI) && !defined (__WIN32__)
8458
8459
8460 # define __WIN32__ 1
8461 # endif
8462
8463
8464
8465
8466
8467
8468
8469
8470
8471
8472
8473
8474
8475
8476
8477 # if defined CYGWIN && defined HAVE_NTGUI
8478 # define boolean jpeg_boolean
8479 # endif
8480 # include <jpeglib.h>
8481 # include <jerror.h>
8482
8483 # ifdef WINDOWSNT
8484
8485
8486 DEF_DLL_FN (void, jpeg_CreateDecompress, (j_decompress_ptr, int, size_t));
8487 DEF_DLL_FN (boolean, jpeg_start_decompress, (j_decompress_ptr));
8488 DEF_DLL_FN (boolean, jpeg_finish_decompress, (j_decompress_ptr));
8489 DEF_DLL_FN (void, jpeg_destroy_decompress, (j_decompress_ptr));
8490 DEF_DLL_FN (int, jpeg_read_header, (j_decompress_ptr, boolean));
8491 DEF_DLL_FN (JDIMENSION, jpeg_read_scanlines,
8492 (j_decompress_ptr, JSAMPARRAY, JDIMENSION));
8493 DEF_DLL_FN (struct jpeg_error_mgr *, jpeg_std_error,
8494 (struct jpeg_error_mgr *));
8495 DEF_DLL_FN (boolean, jpeg_resync_to_restart, (j_decompress_ptr, int));
8496
8497 static bool
8498 init_jpeg_functions (void)
8499 {
8500 HMODULE library;
8501
8502 if (!(library = w32_delayed_load (Qjpeg)))
8503 return 0;
8504
8505 LOAD_DLL_FN (library, jpeg_finish_decompress);
8506 LOAD_DLL_FN (library, jpeg_read_scanlines);
8507 LOAD_DLL_FN (library, jpeg_start_decompress);
8508 LOAD_DLL_FN (library, jpeg_read_header);
8509 LOAD_DLL_FN (library, jpeg_CreateDecompress);
8510 LOAD_DLL_FN (library, jpeg_destroy_decompress);
8511 LOAD_DLL_FN (library, jpeg_std_error);
8512 LOAD_DLL_FN (library, jpeg_resync_to_restart);
8513 return 1;
8514 }
8515
8516 # undef jpeg_CreateDecompress
8517 # undef jpeg_destroy_decompress
8518 # undef jpeg_finish_decompress
8519 # undef jpeg_read_header
8520 # undef jpeg_read_scanlines
8521 # undef jpeg_resync_to_restart
8522 # undef jpeg_start_decompress
8523 # undef jpeg_std_error
8524
8525 # define jpeg_CreateDecompress fn_jpeg_CreateDecompress
8526 # define jpeg_destroy_decompress fn_jpeg_destroy_decompress
8527 # define jpeg_finish_decompress fn_jpeg_finish_decompress
8528 # define jpeg_read_header fn_jpeg_read_header
8529 # define jpeg_read_scanlines fn_jpeg_read_scanlines
8530 # define jpeg_resync_to_restart fn_jpeg_resync_to_restart
8531 # define jpeg_start_decompress fn_jpeg_start_decompress
8532 # define jpeg_std_error fn_jpeg_std_error
8533
8534
8535
8536 static boolean
8537 jpeg_resync_to_restart_wrapper (j_decompress_ptr cinfo, int desired)
8538 {
8539 return jpeg_resync_to_restart (cinfo, desired);
8540 }
8541 # undef jpeg_resync_to_restart
8542 # define jpeg_resync_to_restart jpeg_resync_to_restart_wrapper
8543
8544 # endif
8545
8546 struct my_jpeg_error_mgr
8547 {
8548 struct jpeg_error_mgr pub;
8549 sys_jmp_buf setjmp_buffer;
8550
8551
8552
8553 struct jpeg_decompress_struct cinfo;
8554 enum
8555 {
8556 MY_JPEG_ERROR_EXIT,
8557 MY_JPEG_INVALID_IMAGE_SIZE,
8558 MY_JPEG_CANNOT_CREATE_X
8559 } failure_code;
8560 };
8561
8562
8563 static AVOID
8564 my_error_exit (j_common_ptr cinfo)
8565 {
8566 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
8567 mgr->failure_code = MY_JPEG_ERROR_EXIT;
8568 sys_longjmp (mgr->setjmp_buffer, 1);
8569 }
8570
8571
8572
8573
8574
8575
8576 static void
8577 our_common_init_source (j_decompress_ptr cinfo)
8578 {
8579 }
8580
8581
8582
8583
8584
8585 static void
8586 our_common_term_source (j_decompress_ptr cinfo)
8587 {
8588 }
8589
8590
8591
8592
8593
8594
8595 static JOCTET our_memory_buffer[2];
8596
8597 static boolean
8598 our_memory_fill_input_buffer (j_decompress_ptr cinfo)
8599 {
8600
8601 struct jpeg_source_mgr *src = cinfo->src;
8602
8603 our_memory_buffer[0] = (JOCTET) 0xFF;
8604 our_memory_buffer[1] = (JOCTET) JPEG_EOI;
8605
8606 src->next_input_byte = our_memory_buffer;
8607 src->bytes_in_buffer = 2;
8608 return 1;
8609 }
8610
8611
8612
8613
8614
8615 static void
8616 our_memory_skip_input_data (j_decompress_ptr cinfo, long int num_bytes)
8617 {
8618 struct jpeg_source_mgr *src = cinfo->src;
8619
8620 if (src)
8621 {
8622 if (num_bytes > src->bytes_in_buffer)
8623 ERREXIT (cinfo, JERR_INPUT_EOF);
8624
8625 src->bytes_in_buffer -= num_bytes;
8626 src->next_input_byte += num_bytes;
8627 }
8628 }
8629
8630
8631
8632
8633
8634
8635 static void
8636 jpeg_memory_src (j_decompress_ptr cinfo, JOCTET *data, ptrdiff_t len)
8637 {
8638 struct jpeg_source_mgr *src = cinfo->src;
8639
8640 if (! src)
8641 {
8642
8643 src = cinfo->mem->alloc_small ((j_common_ptr) cinfo,
8644 JPOOL_PERMANENT, sizeof *src);
8645 cinfo->src = src;
8646 src->next_input_byte = data;
8647 }
8648
8649 src->init_source = our_common_init_source;
8650 src->fill_input_buffer = our_memory_fill_input_buffer;
8651 src->skip_input_data = our_memory_skip_input_data;
8652 src->resync_to_restart = jpeg_resync_to_restart;
8653 src->term_source = our_common_term_source;
8654 src->bytes_in_buffer = len;
8655 src->next_input_byte = data;
8656 }
8657
8658
8659 struct jpeg_stdio_mgr
8660 {
8661 struct jpeg_source_mgr mgr;
8662 boolean finished;
8663 FILE *file;
8664 JOCTET *buffer;
8665 };
8666
8667
8668
8669
8670 #define JPEG_STDIO_BUFFER_SIZE 8192
8671
8672
8673
8674
8675
8676 static boolean
8677 our_stdio_fill_input_buffer (j_decompress_ptr cinfo)
8678 {
8679 struct jpeg_stdio_mgr *src;
8680
8681 src = (struct jpeg_stdio_mgr *) cinfo->src;
8682 if (!src->finished)
8683 {
8684 ptrdiff_t bytes;
8685
8686 bytes = fread (src->buffer, 1, JPEG_STDIO_BUFFER_SIZE, src->file);
8687 if (bytes > 0)
8688 src->mgr.bytes_in_buffer = bytes;
8689 else
8690 {
8691 WARNMS (cinfo, JWRN_JPEG_EOF);
8692 src->finished = 1;
8693 src->buffer[0] = (JOCTET) 0xFF;
8694 src->buffer[1] = (JOCTET) JPEG_EOI;
8695 src->mgr.bytes_in_buffer = 2;
8696 }
8697 src->mgr.next_input_byte = src->buffer;
8698 }
8699
8700 return 1;
8701 }
8702
8703
8704
8705
8706
8707 static void
8708 our_stdio_skip_input_data (j_decompress_ptr cinfo, long int num_bytes)
8709 {
8710 struct jpeg_stdio_mgr *src;
8711 src = (struct jpeg_stdio_mgr *) cinfo->src;
8712
8713 while (num_bytes > 0 && !src->finished)
8714 {
8715 if (num_bytes <= src->mgr.bytes_in_buffer)
8716 {
8717 src->mgr.bytes_in_buffer -= num_bytes;
8718 src->mgr.next_input_byte += num_bytes;
8719 break;
8720 }
8721 else
8722 {
8723 num_bytes -= src->mgr.bytes_in_buffer;
8724 src->mgr.bytes_in_buffer = 0;
8725 src->mgr.next_input_byte = NULL;
8726
8727 our_stdio_fill_input_buffer (cinfo);
8728 }
8729 }
8730 }
8731
8732
8733
8734
8735
8736
8737 static void
8738 jpeg_file_src (j_decompress_ptr cinfo, FILE *fp)
8739 {
8740 struct jpeg_stdio_mgr *src = (struct jpeg_stdio_mgr *) cinfo->src;
8741
8742 if (! src)
8743 {
8744
8745 src = cinfo->mem->alloc_small ((j_common_ptr) cinfo,
8746 JPOOL_PERMANENT, sizeof *src);
8747 cinfo->src = (struct jpeg_source_mgr *) src;
8748 src->buffer = cinfo->mem->alloc_small ((j_common_ptr) cinfo,
8749 JPOOL_PERMANENT,
8750 JPEG_STDIO_BUFFER_SIZE);
8751 }
8752
8753 src->file = fp;
8754 src->finished = 0;
8755 src->mgr.init_source = our_common_init_source;
8756 src->mgr.fill_input_buffer = our_stdio_fill_input_buffer;
8757 src->mgr.skip_input_data = our_stdio_skip_input_data;
8758 src->mgr.resync_to_restart = jpeg_resync_to_restart;
8759 src->mgr.term_source = our_common_term_source;
8760 src->mgr.bytes_in_buffer = 0;
8761 src->mgr.next_input_byte = NULL;
8762 }
8763
8764
8765
8766
8767 static bool
8768 jpeg_load_body (struct frame *f, struct image *img,
8769 struct my_jpeg_error_mgr *mgr)
8770 {
8771 Lisp_Object specified_file, specified_data;
8772 FILE *volatile fp = NULL;
8773 JSAMPARRAY buffer;
8774 int row_stride, x, y;
8775 int width, height;
8776 int i, ir, ig, ib;
8777 unsigned long *colors;
8778 Emacs_Pix_Container ximg = NULL;
8779
8780
8781 specified_file = image_spec_value (img->spec, QCfile, NULL);
8782 specified_data = image_spec_value (img->spec, QCdata, NULL);
8783
8784 if (NILP (specified_data))
8785 {
8786 int fd;
8787 Lisp_Object file = image_find_image_file (specified_file);
8788 if (!STRINGP (file)
8789 || (fd = emacs_open (SSDATA (ENCODE_FILE (file)),
8790 O_RDONLY, 0)) < 0)
8791 {
8792 image_error ("Cannot find image file `%s'", specified_file);
8793 return 0;
8794 }
8795
8796 fp = emacs_fdopen (fd, "rb");
8797 if (fp == NULL)
8798 {
8799 image_error ("Cannot open `%s'", file);
8800 return 0;
8801 }
8802 }
8803 else if (!STRINGP (specified_data))
8804 {
8805 image_error ("Invalid image data `%s'", specified_data);
8806 return 0;
8807 }
8808
8809
8810
8811 mgr->cinfo.err = jpeg_std_error (&mgr->pub);
8812 mgr->pub.error_exit = my_error_exit;
8813 if (sys_setjmp (mgr->setjmp_buffer))
8814 {
8815 switch (mgr->failure_code)
8816 {
8817 case MY_JPEG_ERROR_EXIT:
8818 {
8819 char buf[JMSG_LENGTH_MAX];
8820 mgr->cinfo.err->format_message ((j_common_ptr) &mgr->cinfo, buf);
8821 image_error ("Error reading JPEG image `%s': %s",
8822 img->spec, build_string (buf));
8823 break;
8824 }
8825
8826 case MY_JPEG_INVALID_IMAGE_SIZE:
8827 image_size_error ();
8828 break;
8829
8830 case MY_JPEG_CANNOT_CREATE_X:
8831 break;
8832 }
8833
8834
8835 if (fp)
8836 emacs_fclose (fp);
8837 jpeg_destroy_decompress (&mgr->cinfo);
8838
8839
8840 if (ximg)
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;
10454 if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, false))
10455 goto webp_error2;
10456
10457
10458
10459 Emacs_Color bg_color;
10460 if (features.has_alpha)
10461 {
10462 Lisp_Object specified_bg
10463 = image_spec_value (img->spec, QCbackground, NULL);
10464
10465
10466
10467
10468 if (STRINGP (specified_bg))
10469 FRAME_TERMINAL (f)->defined_color_hook (f,
10470 SSDATA (specified_bg),
10471 &bg_color,
10472 false,
10473 false);
10474 else
10475 FRAME_TERMINAL (f)->query_frame_background_color (f, &bg_color);
10476 bg_color.red >>= 8;
10477 bg_color.green >>= 8;
10478 bg_color.blue >>= 8;
10479 }
10480
10481
10482
10483 init_color_table ();
10484
10485 img->corners[TOP_CORNER] = 0;
10486 img->corners[LEFT_CORNER] = 0;
10487 img->corners[BOT_CORNER]
10488 = img->corners[TOP_CORNER] + height;
10489 img->corners[RIGHT_CORNER]
10490 = img->corners[LEFT_CORNER] + width;
10491
10492 uint8_t *p = decoded;
10493 for (int y = 0; y < height; ++y)
10494 {
10495 for (int x = 0; x < width; ++x)
10496 {
10497 int r, g, b;
10498
10499
10500 if (features.has_alpha || anim)
10501 {
10502 float a = (float) p[3] / UINT8_MAX;
10503 r = (int)(a * p[0] + (1 - a) * bg_color.red) << 8;
10504 g = (int)(a * p[1] + (1 - a) * bg_color.green) << 8;
10505 b = (int)(a * p[2] + (1 - a) * bg_color.blue) << 8;
10506 p += 4;
10507 }
10508 else
10509 {
10510 r = *p++ << 8;
10511 g = *p++ << 8;
10512 b = *p++ << 8;
10513 }
10514 PUT_PIXEL (ximg, x, y, lookup_rgb_color (f, r, g, b));
10515 }
10516 }
10517
10518 #ifdef COLOR_TABLE_SUPPORT
10519
10520 img->colors = colors_in_color_table (&img->ncolors);
10521 free_color_table ();
10522 #endif
10523
10524
10525 image_put_x_image (f, img, ximg, 0);
10526
10527 img->width = width;
10528 img->height = height;
10529
10530
10531 img->lisp_data = Fcons (Qcount,
10532 Fcons (make_fixnum (frames),
10533 img->lisp_data));
10534 img->lisp_data = Fcons (Qdelay,
10535 Fcons (make_float (delay / 1000),
10536 img->lisp_data));
10537
10538
10539 if (!anim)
10540 WebPFree (decoded);
10541 if (NILP (specified_data) && !anim)
10542 xfree (contents);
10543 return true;
10544
10545 webp_error2:
10546 if (!anim)
10547 WebPFree (decoded);
10548
10549 webp_error1:
10550 if (NILP (specified_data))
10551 xfree (contents);
10552 return false;
10553 }
10554
10555 #endif
10556
10557
10558 #ifdef HAVE_IMAGEMAGICK
10559
10560
10561
10562
10563
10564
10565
10566
10567 enum imagemagick_keyword_index
10568 {
10569 IMAGEMAGICK_TYPE,
10570 IMAGEMAGICK_DATA,
10571 IMAGEMAGICK_FILE,
10572 IMAGEMAGICK_ASCENT,
10573 IMAGEMAGICK_MARGIN,
10574 IMAGEMAGICK_RELIEF,
10575 IMAGEMAGICK_ALGORITHM,
10576 IMAGEMAGICK_HEURISTIC_MASK,
10577 IMAGEMAGICK_MASK,
10578 IMAGEMAGICK_BACKGROUND,
10579 IMAGEMAGICK_HEIGHT,
10580 IMAGEMAGICK_WIDTH,
10581 IMAGEMAGICK_MAX_HEIGHT,
10582 IMAGEMAGICK_MAX_WIDTH,
10583 IMAGEMAGICK_FORMAT,
10584 IMAGEMAGICK_ROTATION,
10585 IMAGEMAGICK_CROP,
10586 IMAGEMAGICK_LAST
10587 };
10588
10589
10590
10591
10592 static struct image_keyword imagemagick_format[IMAGEMAGICK_LAST] =
10593 {
10594 {":type", IMAGE_SYMBOL_VALUE, 1},
10595 {":data", IMAGE_STRING_VALUE, 0},
10596 {":file", IMAGE_STRING_VALUE, 0},
10597 {":ascent", IMAGE_ASCENT_VALUE, 0},
10598 {":margin", IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR, 0},
10599 {":relief", IMAGE_INTEGER_VALUE, 0},
10600 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10601 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10602 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10603 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
10604 {":height", IMAGE_INTEGER_VALUE, 0},
10605 {":width", IMAGE_INTEGER_VALUE, 0},
10606 {":max-height", IMAGE_INTEGER_VALUE, 0},
10607 {":max-width", IMAGE_INTEGER_VALUE, 0},
10608 {":format", IMAGE_SYMBOL_VALUE, 0},
10609 {":rotation", IMAGE_NUMBER_VALUE, 0},
10610 {":crop", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
10611 };
10612
10613
10614
10615 static void
10616 imagemagick_clear_image (struct frame *f,
10617 struct image *img)
10618 {
10619 image_clear_image (f, img);
10620 }
10621
10622
10623
10624
10625
10626 static bool
10627 imagemagick_image_p (Lisp_Object object)
10628 {
10629 struct image_keyword fmt[IMAGEMAGICK_LAST];
10630 memcpy (fmt, imagemagick_format, sizeof fmt);
10631
10632 if (!parse_image_spec (object, fmt, IMAGEMAGICK_LAST, Qimagemagick))
10633 return 0;
10634
10635
10636 return fmt[IMAGEMAGICK_FILE].count + fmt[IMAGEMAGICK_DATA].count == 1;
10637 }
10638
10639
10640
10641 #define DrawRectangle DrawRectangleGif
10642
10643 #ifdef HAVE_IMAGEMAGICK7
10644 # include <MagickWand/MagickWand.h>
10645 # include <MagickCore/version.h>
10646
10647 # define PixelSetMagickColor PixelSetPixelColor
10648 typedef PixelInfo MagickPixelPacket;
10649 #else
10650 # include <wand/MagickWand.h>
10651 # include <magick/version.h>
10652 #endif
10653
10654
10655
10656 #if 0x653 <= MagickLibVersion && MagickLibVersion <= 0x665
10657 extern WandExport void PixelGetMagickColor (const PixelWand *,
10658 MagickPixelPacket *);
10659 #endif
10660
10661 static void
10662 imagemagick_initialize (void)
10663 {
10664 static bool imagemagick_initialized;
10665 if (!imagemagick_initialized)
10666 {
10667 imagemagick_initialized = true;
10668 MagickWandGenesis ();
10669 }
10670 }
10671
10672
10673
10674
10675 static void
10676 imagemagick_error (MagickWand *wand)
10677 {
10678 char *description;
10679 ExceptionType severity;
10680
10681 description = MagickGetException (wand, &severity);
10682 image_error ("ImageMagick error: %s", build_string (description));
10683 MagickRelinquishMemory (description);
10684 }
10685
10686
10687
10688
10689 static char *
10690 imagemagick_filename_hint (Lisp_Object spec, char hint_buffer[MaxTextExtent])
10691 {
10692 Lisp_Object symbol = intern ("image-format-suffixes");
10693 Lisp_Object val = find_symbol_value (symbol);
10694 Lisp_Object format;
10695
10696 if (! CONSP (val))
10697 return NULL;
10698
10699 format = image_spec_value (spec, intern (":format"), NULL);
10700 val = Fcar_safe (Fcdr_safe (Fassq (format, val)));
10701 if (! STRINGP (val))
10702 return NULL;
10703
10704
10705
10706 snprintf (hint_buffer, MaxTextExtent, "/tmp/foo.%s", SSDATA (val));
10707 return hint_buffer;
10708 }
10709
10710
10711
10712
10713
10714
10715
10716
10717
10718
10719
10720
10721
10722 struct animation_cache
10723 {
10724 MagickWand *wand;
10725 int index;
10726 struct timespec update_time;
10727 struct animation_cache *next;
10728 char signature[FLEXIBLE_ARRAY_MEMBER];
10729 };
10730
10731 static struct animation_cache *animation_cache = NULL;
10732
10733 static struct animation_cache *
10734 imagemagick_create_cache (char *signature)
10735 {
10736 struct animation_cache *cache
10737 = xmalloc (FLEXSIZEOF (struct animation_cache, signature,
10738 strlen (signature) + 1));
10739 cache->wand = 0;
10740 cache->index = 0;
10741 cache->next = 0;
10742 strcpy (cache->signature, signature);
10743 return cache;
10744 }
10745
10746
10747
10748 static void
10749 imagemagick_prune_animation_cache (bool clear)
10750 {
10751 struct animation_cache **pcache = &animation_cache;
10752 struct timespec old = timespec_sub (current_timespec (),
10753 make_timespec (60, 0));
10754
10755 while (*pcache)
10756 {
10757 struct animation_cache *cache = *pcache;
10758 if (clear || timespec_cmp (old, cache->update_time) > 0)
10759 {
10760 if (cache->wand)
10761 DestroyMagickWand (cache->wand);
10762 *pcache = cache->next;
10763 xfree (cache);
10764 }
10765 else
10766 pcache = &cache->next;
10767 }
10768 }
10769
10770 static struct animation_cache *
10771 imagemagick_get_animation_cache (MagickWand *wand)
10772 {
10773 char *signature = MagickGetImageSignature (wand);
10774 struct animation_cache *cache;
10775 struct animation_cache **pcache = &animation_cache;
10776
10777 imagemagick_prune_animation_cache (false);
10778
10779 while (1)
10780 {
10781 cache = *pcache;
10782 if (! cache)
10783 {
10784 *pcache = cache = imagemagick_create_cache (signature);
10785 break;
10786 }
10787 if (strcmp (signature, cache->signature) == 0)
10788 break;
10789 pcache = &cache->next;
10790 }
10791
10792 DestroyString (signature);
10793 cache->update_time = current_timespec ();
10794 return cache;
10795 }
10796
10797 static MagickWand *
10798 imagemagick_compute_animated_image (MagickWand *super_wand, int ino)
10799 {
10800 int i;
10801 MagickWand *composite_wand;
10802 size_t dest_width, dest_height;
10803 struct animation_cache *cache = imagemagick_get_animation_cache (super_wand);
10804
10805 MagickSetIteratorIndex (super_wand, 0);
10806
10807 if (ino == 0 || cache->wand == NULL || cache->index > ino)
10808 {
10809 composite_wand = MagickGetImage (super_wand);
10810 if (cache->wand)
10811 DestroyMagickWand (cache->wand);
10812 }
10813 else
10814 composite_wand = cache->wand;
10815
10816 dest_height = MagickGetImageHeight (composite_wand);
10817
10818 for (i = max (1, cache->index + 1); i <= ino; i++)
10819 {
10820 MagickWand *sub_wand;
10821 PixelIterator *source_iterator, *dest_iterator;
10822 PixelWand **source, **dest;
10823 size_t source_width, source_height;
10824 ssize_t source_left, source_top;
10825 MagickPixelPacket pixel;
10826 DisposeType dispose;
10827 ptrdiff_t lines = 0;
10828
10829 MagickSetIteratorIndex (super_wand, i);
10830 sub_wand = MagickGetImage (super_wand);
10831
10832 MagickGetImagePage (sub_wand, &source_width, &source_height,
10833 &source_left, &source_top);
10834
10835
10836 dispose = MagickGetImageDispose (sub_wand);
10837
10838 source_iterator = NewPixelIterator (sub_wand);
10839 if (! source_iterator)
10840 {
10841 DestroyMagickWand (composite_wand);
10842 DestroyMagickWand (sub_wand);
10843 cache->wand = NULL;
10844 image_error ("Imagemagick pixel iterator creation failed");
10845 return NULL;
10846 }
10847
10848 dest_iterator = NewPixelIterator (composite_wand);
10849 if (! dest_iterator)
10850 {
10851 DestroyMagickWand (composite_wand);
10852 DestroyMagickWand (sub_wand);
10853 DestroyPixelIterator (source_iterator);
10854 cache->wand = NULL;
10855 image_error ("Imagemagick pixel iterator creation failed");
10856 return NULL;
10857 }
10858
10859
10860
10861 if (source_top > 0)
10862 {
10863 PixelSetIteratorRow (dest_iterator, source_top);
10864 lines = source_top;
10865 }
10866
10867 while ((source = PixelGetNextIteratorRow (source_iterator, &source_width))
10868 != NULL)
10869 {
10870 ptrdiff_t x;
10871
10872
10873
10874 if (++lines >= dest_height)
10875 break;
10876
10877 dest = PixelGetNextIteratorRow (dest_iterator, &dest_width);
10878 for (x = 0; x < source_width; x++)
10879 {
10880
10881
10882 if (x + source_left >= dest_width)
10883 break;
10884
10885
10886
10887 if (dispose == BackgroundDispose || PixelGetAlpha (source[x]))
10888 {
10889 PixelGetMagickColor (source[x], &pixel);
10890 PixelSetMagickColor (dest[x + source_left], &pixel);
10891 }
10892 }
10893 PixelSyncIterator (dest_iterator);
10894 }
10895
10896 DestroyPixelIterator (source_iterator);
10897 DestroyPixelIterator (dest_iterator);
10898 DestroyMagickWand (sub_wand);
10899 }
10900
10901
10902
10903 cache->wand = CloneMagickWand (composite_wand);
10904 cache->index = ino;
10905
10906 return composite_wand;
10907 }
10908
10909
10910
10911
10912
10913
10914
10915
10916
10917
10918
10919
10920
10921
10922 static bool
10923 imagemagick_load_image (struct frame *f, struct image *img,
10924 unsigned char *contents, unsigned int size,
10925 char *filename)
10926 {
10927 int width, height;
10928 size_t image_width, image_height;
10929 MagickBooleanType status;
10930 Emacs_Pix_Container ximg;
10931 int x, y;
10932 MagickWand *image_wand;
10933 PixelIterator *iterator;
10934 PixelWand **pixels, *bg_wand = NULL;
10935 MagickPixelPacket pixel;
10936 Lisp_Object image;
10937 #ifndef DONT_CREATE_TRANSFORMED_IMAGEMAGICK_IMAGE
10938 Lisp_Object value;
10939 #endif
10940 Lisp_Object crop;
10941 EMACS_INT ino;
10942 int desired_width, desired_height;
10943 #ifndef DONT_CREATE_TRANSFORMED_IMAGEMAGICK_IMAGE
10944 double rotation;
10945 #endif
10946 char hint_buffer[MaxTextExtent];
10947 char *filename_hint = NULL;
10948 imagemagick_initialize ();
10949
10950
10951
10952
10953
10954
10955 image = image_spec_value (img->spec, QCindex, NULL);
10956 ino = FIXNUMP (image) ? XFIXNAT (image) : 0;
10957 image_wand = NewMagickWand ();
10958
10959 if (filename)
10960 status = MagickReadImage (image_wand, filename);
10961 else
10962 {
10963 Lisp_Object lwidth = image_spec_value (img->spec, QCwidth, NULL);
10964 Lisp_Object lheight = image_spec_value (img->spec, QCheight, NULL);
10965
10966 if (FIXNATP (lwidth) && FIXNATP (lheight))
10967 {
10968 MagickSetSize (image_wand, XFIXNAT (lwidth), XFIXNAT (lheight));
10969 MagickSetDepth (image_wand, 8);
10970 }
10971 filename_hint = imagemagick_filename_hint (img->spec, hint_buffer);
10972 MagickSetFilename (image_wand, filename_hint);
10973 status = MagickReadImageBlob (image_wand, contents, size);
10974 }
10975
10976 if (status == MagickFalse)
10977 {
10978 imagemagick_error (image_wand);
10979 DestroyMagickWand (image_wand);
10980 return 0;
10981 }
10982
10983 #if defined HAVE_MAGICKAUTOORIENTIMAGE \
10984 || HAVE_DECL_MAGICKAUTOORIENTIMAGE
10985
10986
10987 if (NILP (image_spec_value (img->spec, QCrotation, NULL)))
10988 if (MagickAutoOrientImage (image_wand) == MagickFalse)
10989 {
10990 image_error ("Error applying automatic orientation in image `%s'", img->spec);
10991 DestroyMagickWand (image_wand);
10992 return 0;
10993 }
10994 #endif
10995
10996 if (ino < 0 || ino >= MagickGetNumberImages (image_wand))
10997 {
10998 image_error ("Invalid image number `%s' in image `%s'", image, img->spec);
10999 DestroyMagickWand (image_wand);
11000 return 0;
11001 }
11002
11003 if (MagickGetImageDelay (image_wand) > 0)
11004 img->lisp_data =
11005 Fcons (Qdelay,
11006 Fcons (make_float (MagickGetImageDelay (image_wand) / 100.0),
11007 img->lisp_data));
11008
11009 if (MagickGetNumberImages (image_wand) > 1)
11010 img->lisp_data =
11011 Fcons (Qcount,
11012 Fcons (make_fixnum (MagickGetNumberImages (image_wand)),
11013 img->lisp_data));
11014
11015
11016
11017 if (MagickGetNumberImages (image_wand) > 1)
11018 {
11019
11020
11021 if (MagickGetImageDelay (image_wand) > 0)
11022 {
11023 MagickWand *super_wand = image_wand;
11024 image_wand = imagemagick_compute_animated_image (super_wand, ino);
11025 if (! image_wand)
11026 image_wand = super_wand;
11027 else
11028 DestroyMagickWand (super_wand);
11029 }
11030 else
11031
11032
11033
11034 {
11035 MagickWand *super_wand = image_wand;
11036
11037 MagickSetIteratorIndex (super_wand, ino);
11038 image_wand = MagickGetImage (super_wand);
11039 DestroyMagickWand (super_wand);
11040 }
11041 }
11042
11043
11044 {
11045 Emacs_Color bgcolor;
11046 Lisp_Object specified_bg;
11047
11048 specified_bg = image_spec_value (img->spec, QCbackground, NULL);
11049 if (!STRINGP (specified_bg)
11050 || !FRAME_TERMINAL (f)->defined_color_hook (f,
11051 SSDATA (specified_bg),
11052 &bgcolor,
11053 false,
11054 false))
11055 FRAME_TERMINAL (f)->query_frame_background_color (f, &bgcolor);
11056
11057 bg_wand = NewPixelWand ();
11058 PixelSetRed (bg_wand, (double) bgcolor.red / 65535);
11059 PixelSetGreen (bg_wand, (double) bgcolor.green / 65535);
11060 PixelSetBlue (bg_wand, (double) bgcolor.blue / 65535);
11061 }
11062
11063 #ifndef DONT_CREATE_TRANSFORMED_IMAGEMAGICK_IMAGE
11064 compute_image_size (MagickGetImageWidth (image_wand),
11065 MagickGetImageHeight (image_wand),
11066 img, &desired_width, &desired_height);
11067 #else
11068 desired_width = desired_height = -1;
11069 #endif
11070
11071 if (desired_width != -1 && desired_height != -1)
11072 {
11073 status = MagickScaleImage (image_wand, desired_width, desired_height);
11074 if (status == MagickFalse)
11075 {
11076 image_error ("Imagemagick scale failed");
11077 imagemagick_error (image_wand);
11078 goto imagemagick_error;
11079 }
11080 }
11081
11082
11083
11084 crop = image_spec_value (img->spec, QCcrop, NULL);
11085
11086 if (CONSP (crop) && TYPE_RANGED_FIXNUMP (size_t, XCAR (crop)))
11087 {
11088
11089
11090
11091
11092
11093 size_t crop_width = XFIXNUM (XCAR (crop));
11094 crop = XCDR (crop);
11095 if (CONSP (crop) && TYPE_RANGED_FIXNUMP (size_t, XCAR (crop)))
11096 {
11097 size_t crop_height = XFIXNUM (XCAR (crop));
11098 crop = XCDR (crop);
11099 if (CONSP (crop) && TYPE_RANGED_FIXNUMP (ssize_t, XCAR (crop)))
11100 {
11101 ssize_t crop_x = XFIXNUM (XCAR (crop));
11102 crop = XCDR (crop);
11103 if (CONSP (crop) && TYPE_RANGED_FIXNUMP (ssize_t, XCAR (crop)))
11104 {
11105 ssize_t crop_y = XFIXNUM (XCAR (crop));
11106 MagickCropImage (image_wand, crop_width, crop_height,
11107 crop_x, crop_y);
11108 }
11109 }
11110 }
11111 }
11112
11113 #ifndef DONT_CREATE_TRANSFORMED_IMAGEMAGICK_IMAGE
11114
11115
11116
11117
11118
11119
11120 value = image_spec_value (img->spec, QCrotation, NULL);
11121 if (FLOATP (value))
11122 {
11123 rotation = XFLOAT_DATA (value);
11124 status = MagickRotateImage (image_wand, bg_wand, rotation);
11125 if (status == MagickFalse)
11126 {
11127 image_error ("Imagemagick image rotate failed");
11128 imagemagick_error (image_wand);
11129 goto imagemagick_error;
11130 }
11131 }
11132 #endif
11133
11134
11135
11136
11137
11138 {
11139 MagickWand *new_wand;
11140 MagickSetImageBackgroundColor (image_wand, bg_wand);
11141 #if defined HAVE_MAGICKMERGEIMAGELAYERS \
11142 || HAVE_DECL_MAGICKMERGEIMAGELAYERS
11143 new_wand = MagickMergeImageLayers (image_wand, MergeLayer);
11144 #else
11145 new_wand = MagickFlattenImages (image_wand);
11146 #endif
11147 DestroyMagickWand (image_wand);
11148 image_wand = new_wand;
11149 }
11150
11151
11152
11153 image_height = MagickGetImageHeight (image_wand);
11154 image_width = MagickGetImageWidth (image_wand);
11155
11156 if (! (image_width <= INT_MAX && image_height <= INT_MAX
11157 && check_image_size (f, image_width, image_height)))
11158 {
11159 image_size_error ();
11160 goto imagemagick_error;
11161 }
11162
11163 width = image_width;
11164 height = image_height;
11165
11166
11167
11168
11169 init_color_table ();
11170
11171 #if (defined (HAVE_MAGICKEXPORTIMAGEPIXELS) \
11172 || HAVE_DECL_MAGICKEXPORTIMAGEPIXELS) \
11173 && ! defined (HAVE_NS) && ! defined (HAVE_HAIKU)
11174 if (imagemagick_render_type != 0)
11175 {
11176
11177
11178
11179 void *dataptr;
11180 int imagedepth = 24;
11181 const char *exportdepth = imagedepth <= 8 ? "I" : "BGRP";
11182
11183 if (!image_create_x_image_and_pixmap (f, img, width, height, imagedepth,
11184 &ximg, 0))
11185 {
11186 #ifdef COLOR_TABLE_SUPPORT
11187 free_color_table ();
11188 #endif
11189 image_error ("Imagemagick X bitmap allocation failure");
11190 goto imagemagick_error;
11191 }
11192 dataptr = ximg->data;
11193
11194
11195
11196
11197
11198
11199
11200
11201
11202
11203
11204
11205
11206
11207
11208
11209
11210
11211
11212
11213 int pixelwidth = CharPixel;
11214 MagickExportImagePixels (image_wand, 0, 0, width, height,
11215 exportdepth, pixelwidth, dataptr);
11216 }
11217 else
11218 #endif
11219 {
11220 size_t image_height;
11221 double quantum_range = QuantumRange;
11222 MagickRealType color_scale = 65535.0 / quantum_range;
11223
11224 if (!image_create_x_image_and_pixmap (f, img, width, height, 0,
11225 &ximg, 0))
11226 {
11227 #ifdef COLOR_TABLE_SUPPORT
11228 free_color_table ();
11229 #endif
11230 image_error ("Imagemagick X bitmap allocation failure");
11231 goto imagemagick_error;
11232 }
11233
11234
11235
11236
11237
11238
11239 iterator = NewPixelIterator (image_wand);
11240 if (! iterator)
11241 {
11242 #ifdef COLOR_TABLE_SUPPORT
11243 free_color_table ();
11244 #endif
11245 image_destroy_x_image (ximg);
11246 image_error ("Imagemagick pixel iterator creation failed");
11247 goto imagemagick_error;
11248 }
11249
11250 image_height = MagickGetImageHeight (image_wand);
11251 for (y = 0; y < image_height; y++)
11252 {
11253 size_t row_width;
11254 pixels = PixelGetNextIteratorRow (iterator, &row_width);
11255 if (! pixels)
11256 break;
11257 int xlim = min (row_width, width);
11258 for (x = 0; x < xlim; x++)
11259 {
11260 PixelGetMagickColor (pixels[x], &pixel);
11261 PUT_PIXEL (ximg, x, y,
11262 lookup_rgb_color (f,
11263 color_scale * pixel.red,
11264 color_scale * pixel.green,
11265 color_scale * pixel.blue));
11266 }
11267 }
11268 DestroyPixelIterator (iterator);
11269 }
11270
11271 #ifdef COLOR_TABLE_SUPPORT
11272
11273 img->colors = colors_in_color_table (&img->ncolors);
11274 free_color_table ();
11275 #endif
11276
11277 img->width = width;
11278 img->height = height;
11279
11280
11281 image_put_x_image (f, img, ximg, 0);
11282
11283
11284 DestroyMagickWand (image_wand);
11285 if (bg_wand) DestroyPixelWand (bg_wand);
11286
11287
11288
11289
11290
11291
11292 return 1;
11293
11294 imagemagick_error:
11295 DestroyMagickWand (image_wand);
11296 if (bg_wand) DestroyPixelWand (bg_wand);
11297
11298
11299 image_error ("Error parsing IMAGEMAGICK image `%s'", img->spec);
11300 return 0;
11301 }
11302
11303
11304
11305
11306
11307
11308 static bool
11309 imagemagick_load (struct frame *f, struct image *img)
11310 {
11311 bool success_p = 0;
11312 Lisp_Object file_name;
11313
11314
11315 file_name = image_spec_value (img->spec, QCfile, NULL);
11316 if (STRINGP (file_name))
11317 {
11318 Lisp_Object file = image_find_image_file (file_name);
11319 if (!STRINGP (file))
11320 {
11321 image_error ("Cannot find image file `%s'", file_name);
11322 return 0;
11323 }
11324 file = ENCODE_FILE (file);
11325 #ifdef WINDOWSNT
11326 file = ansi_encode_filename (file);
11327 #endif
11328 success_p = imagemagick_load_image (f, img, 0, 0, SSDATA (file));
11329 }
11330
11331
11332 else
11333 {
11334 Lisp_Object data;
11335
11336 data = image_spec_value (img->spec, QCdata, NULL);
11337 if (!STRINGP (data))
11338 {
11339 image_error ("Invalid image data `%s'", data);
11340 return 0;
11341 }
11342 success_p = imagemagick_load_image (f, img, SDATA (data),
11343 SBYTES (data), NULL);
11344 }
11345
11346 return success_p;
11347 }
11348
11349 DEFUN ("imagemagick-types", Fimagemagick_types, Simagemagick_types, 0, 0, 0,
11350 doc:
11351
11352
11353
11354
11355
11356
11357
11358 )
11359 (void)
11360 {
11361 Lisp_Object typelist = Qnil;
11362 size_t numf = 0;
11363 ExceptionInfo *ex;
11364 char **imtypes;
11365 size_t i;
11366
11367 imagemagick_initialize ();
11368 ex = AcquireExceptionInfo ();
11369 imtypes = GetMagickList ("*", &numf, ex);
11370 DestroyExceptionInfo (ex);
11371
11372 for (i = 0; i < numf; i++)
11373 {
11374 Lisp_Object imagemagicktype = intern (imtypes[i]);
11375 typelist = Fcons (imagemagicktype, typelist);
11376 imtypes[i] = MagickRelinquishMemory (imtypes[i]);
11377 }
11378
11379 MagickRelinquishMemory (imtypes);
11380 return Fnreverse (typelist);
11381 }
11382
11383 #endif
11384
11385
11386
11387
11388
11389
11390
11391 #ifdef HAVE_RSVG
11392
11393
11394
11395 static bool svg_load_image (struct frame *, struct image *,
11396 char *, ptrdiff_t, char *);
11397
11398
11399
11400 enum svg_keyword_index
11401 {
11402 SVG_TYPE,
11403 SVG_DATA,
11404 SVG_FILE,
11405 SVG_BASE_URI,
11406 SVG_CSS,
11407 SVG_ASCENT,
11408 SVG_MARGIN,
11409 SVG_RELIEF,
11410 SVG_ALGORITHM,
11411 SVG_HEURISTIC_MASK,
11412 SVG_MASK,
11413 SVG_FOREGROUND,
11414 SVG_BACKGROUND,
11415 SVG_LAST
11416 };
11417
11418
11419
11420
11421 static const struct image_keyword svg_format[SVG_LAST] =
11422 {
11423 {":type", IMAGE_SYMBOL_VALUE, 1},
11424 {":data", IMAGE_STRING_VALUE, 0},
11425 {":file", IMAGE_STRING_VALUE, 0},
11426 {":base-uri", IMAGE_STRING_VALUE, 0},
11427 {":css", IMAGE_STRING_VALUE, 0},
11428 {":ascent", IMAGE_ASCENT_VALUE, 0},
11429 {":margin", IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR, 0},
11430 {":relief", IMAGE_INTEGER_VALUE, 0},
11431 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11432 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11433 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11434 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
11435 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
11436 };
11437
11438
11439
11440
11441
11442 static bool
11443 svg_image_p (Lisp_Object object)
11444 {
11445 struct image_keyword fmt[SVG_LAST];
11446 memcpy (fmt, svg_format, sizeof fmt);
11447
11448 if (!parse_image_spec (object, fmt, SVG_LAST, Qsvg))
11449 return 0;
11450
11451
11452 return fmt[SVG_FILE].count + fmt[SVG_DATA].count == 1;
11453 }
11454
11455
11456
11457
11458 # ifdef WINDOWSNT
11459 # if (__W32API_MAJOR_VERSION + (__W32API_MINOR_VERSION >= 18)) >= 4
11460 # define W32_SAVE_MINGW_VERSION __MINGW_MAJOR_VERSION
11461 # undef __MINGW_MAJOR_VERSION
11462 # define __MINGW_MAJOR_VERSION 4
11463 # endif
11464 # endif
11465
11466 # include <librsvg/rsvg.h>
11467
11468
11469 # ifndef LIBRSVG_CHECK_VERSION
11470 # define LIBRSVG_CHECK_VERSION(v, w, x) false
11471 # endif
11472
11473 # ifdef WINDOWSNT
11474
11475
11476 # if defined W32_SAVE_MINGW_VERSION && defined __MINGW_MAJOR_VERSION
11477 # undef __MINGW_MAJOR_VERSION
11478 # define __MINGW_MAJOR_VERSION W32_SAVE_MINGW_VERSION
11479 # ifdef __MINGW_MAJOR_VERSION
11480 # undef W32_SAVE_MINGW_VERSION
11481 # endif
11482 # endif
11483
11484
11485 # if LIBRSVG_CHECK_VERSION (2, 32, 0)
11486 DEF_DLL_FN (GFile *, g_file_new_for_path, (char const *));
11487 DEF_DLL_FN (GInputStream *, g_memory_input_stream_new_from_data,
11488 (void const *, gssize, GDestroyNotify));
11489 DEF_DLL_FN (RsvgHandle *, rsvg_handle_new_from_stream_sync,
11490 (GInputStream *, GFile *, RsvgHandleFlags, GCancellable *,
11491 GError **error));
11492 # else
11493 DEF_DLL_FN (RsvgHandle *, rsvg_handle_new, (void));
11494 DEF_DLL_FN (void, rsvg_handle_set_base_uri, (RsvgHandle *, const char *));
11495 DEF_DLL_FN (gboolean, rsvg_handle_write,
11496 (RsvgHandle *, const guchar *, gsize, GError **));
11497 DEF_DLL_FN (gboolean, rsvg_handle_close, (RsvgHandle *, GError **));
11498 # endif
11499
11500 DEF_DLL_FN (void, rsvg_handle_set_dpi_x_y,
11501 (RsvgHandle * handle, double dpi_x, double dpi_y));
11502
11503 # if LIBRSVG_CHECK_VERSION (2, 52, 1)
11504 DEF_DLL_FN (gboolean, rsvg_handle_get_intrinsic_size_in_pixels,
11505 (RsvgHandle *, gdouble *, gdouble *));
11506 # endif
11507 # if LIBRSVG_CHECK_VERSION (2, 46, 0)
11508 DEF_DLL_FN (void, rsvg_handle_get_intrinsic_dimensions,
11509 (RsvgHandle *, gboolean *, RsvgLength *, gboolean *,
11510 RsvgLength *, gboolean *, RsvgRectangle *));
11511 DEF_DLL_FN (gboolean, rsvg_handle_get_geometry_for_layer,
11512 (RsvgHandle *, const char *, const RsvgRectangle *,
11513 RsvgRectangle *, RsvgRectangle *, GError **));
11514 # else
11515 DEF_DLL_FN (void, rsvg_handle_get_dimensions,
11516 (RsvgHandle *, RsvgDimensionData *));
11517 # endif
11518
11519 # if LIBRSVG_CHECK_VERSION (2, 48, 0)
11520 DEF_DLL_FN (gboolean, rsvg_handle_set_stylesheet,
11521 (RsvgHandle *, const guint8 *, gsize, GError **));
11522 # endif
11523 DEF_DLL_FN (GdkPixbuf *, rsvg_handle_get_pixbuf, (RsvgHandle *));
11524 DEF_DLL_FN (int, gdk_pixbuf_get_width, (const GdkPixbuf *));
11525 DEF_DLL_FN (int, gdk_pixbuf_get_height, (const GdkPixbuf *));
11526 DEF_DLL_FN (guchar *, gdk_pixbuf_get_pixels, (const GdkPixbuf *));
11527 DEF_DLL_FN (int, gdk_pixbuf_get_rowstride, (const GdkPixbuf *));
11528 DEF_DLL_FN (GdkColorspace, gdk_pixbuf_get_colorspace, (const GdkPixbuf *));
11529 DEF_DLL_FN (int, gdk_pixbuf_get_n_channels, (const GdkPixbuf *));
11530 DEF_DLL_FN (gboolean, gdk_pixbuf_get_has_alpha, (const GdkPixbuf *));
11531 DEF_DLL_FN (int, gdk_pixbuf_get_bits_per_sample, (const GdkPixbuf *));
11532
11533 # if ! GLIB_CHECK_VERSION (2, 36, 0)
11534 DEF_DLL_FN (void, g_type_init, (void));
11535 # endif
11536 DEF_DLL_FN (void, g_object_unref, (gpointer));
11537 DEF_DLL_FN (void, g_error_free, (GError *));
11538
11539 static bool
11540 init_svg_functions (void)
11541 {
11542 HMODULE library, gdklib = NULL, glib = NULL, gobject = NULL, giolib = NULL;
11543
11544 if (!(glib = w32_delayed_load (Qglib))
11545 || !(gobject = w32_delayed_load (Qgobject))
11546 # if LIBRSVG_CHECK_VERSION (2, 32, 0)
11547 || !(giolib = w32_delayed_load (Qgio))
11548 # endif
11549 || !(gdklib = w32_delayed_load (Qgdk_pixbuf))
11550 || !(library = w32_delayed_load (Qsvg)))
11551 {
11552 if (gdklib) FreeLibrary (gdklib);
11553 if (giolib) FreeLibrary (giolib);
11554 if (gobject) FreeLibrary (gobject);
11555 if (glib) FreeLibrary (glib);
11556 return 0;
11557 }
11558
11559 #if LIBRSVG_CHECK_VERSION (2, 32, 0)
11560 LOAD_DLL_FN (giolib, g_file_new_for_path);
11561 LOAD_DLL_FN (giolib, g_memory_input_stream_new_from_data);
11562 LOAD_DLL_FN (library, rsvg_handle_new_from_stream_sync);
11563 #else
11564 LOAD_DLL_FN (library, rsvg_handle_new);
11565 LOAD_DLL_FN (library, rsvg_handle_set_base_uri);
11566 LOAD_DLL_FN (library, rsvg_handle_write);
11567 LOAD_DLL_FN (library, rsvg_handle_close);
11568 #endif
11569 LOAD_DLL_FN (library, rsvg_handle_set_dpi_x_y);
11570 #if LIBRSVG_CHECK_VERSION (2, 52, 1)
11571 LOAD_DLL_FN (library, rsvg_handle_get_intrinsic_size_in_pixels);
11572 #endif
11573 #if LIBRSVG_CHECK_VERSION (2, 46, 0)
11574 LOAD_DLL_FN (library, rsvg_handle_get_intrinsic_dimensions);
11575 LOAD_DLL_FN (library, rsvg_handle_get_geometry_for_layer);
11576 #else
11577 LOAD_DLL_FN (library, rsvg_handle_get_dimensions);
11578 #endif
11579 #if LIBRSVG_CHECK_VERSION (2, 48, 0)
11580 LOAD_DLL_FN (library, rsvg_handle_set_stylesheet);
11581 #endif
11582 LOAD_DLL_FN (library, rsvg_handle_get_pixbuf);
11583
11584 LOAD_DLL_FN (gdklib, gdk_pixbuf_get_width);
11585 LOAD_DLL_FN (gdklib, gdk_pixbuf_get_height);
11586 LOAD_DLL_FN (gdklib, gdk_pixbuf_get_pixels);
11587 LOAD_DLL_FN (gdklib, gdk_pixbuf_get_rowstride);
11588 LOAD_DLL_FN (gdklib, gdk_pixbuf_get_colorspace);
11589 LOAD_DLL_FN (gdklib, gdk_pixbuf_get_n_channels);
11590 LOAD_DLL_FN (gdklib, gdk_pixbuf_get_has_alpha);
11591 LOAD_DLL_FN (gdklib, gdk_pixbuf_get_bits_per_sample);
11592
11593 # if ! GLIB_CHECK_VERSION (2, 36, 0)
11594 LOAD_DLL_FN (gobject, g_type_init);
11595 # endif
11596 LOAD_DLL_FN (gobject, g_object_unref);
11597 LOAD_DLL_FN (glib, g_error_free);
11598
11599 return 1;
11600 }
11601
11602
11603
11604
11605 # undef gdk_pixbuf_get_bits_per_sample
11606 # undef gdk_pixbuf_get_colorspace
11607 # undef gdk_pixbuf_get_has_alpha
11608 # undef gdk_pixbuf_get_height
11609 # undef gdk_pixbuf_get_n_channels
11610 # undef gdk_pixbuf_get_pixels
11611 # undef gdk_pixbuf_get_rowstride
11612 # undef gdk_pixbuf_get_width
11613 # undef g_error_free
11614 # undef g_object_unref
11615 # undef g_type_init
11616 # if LIBRSVG_CHECK_VERSION (2, 52, 1)
11617 # undef rsvg_handle_get_intrinsic_size_in_pixels
11618 # endif
11619 # if LIBRSVG_CHECK_VERSION (2, 46, 0)
11620 # undef rsvg_handle_get_intrinsic_dimensions
11621 # undef rsvg_handle_get_geometry_for_layer
11622 # else
11623 # undef rsvg_handle_get_dimensions
11624 # endif
11625 # if LIBRSVG_CHECK_VERSION (2, 48, 0)
11626 # undef rsvg_handle_set_stylesheet
11627 # endif
11628 # undef rsvg_handle_get_pixbuf
11629 # if LIBRSVG_CHECK_VERSION (2, 32, 0)
11630 # undef g_file_new_for_path
11631 # undef g_memory_input_stream_new_from_data
11632 # undef rsvg_handle_new_from_stream_sync
11633 # else
11634 # undef rsvg_handle_close
11635 # undef rsvg_handle_new
11636 # undef rsvg_handle_set_base_uri
11637 # undef rsvg_handle_write
11638 # endif
11639 # undef rsvg_handle_set_dpi_x_y
11640
11641 # define gdk_pixbuf_get_bits_per_sample fn_gdk_pixbuf_get_bits_per_sample
11642 # define gdk_pixbuf_get_colorspace fn_gdk_pixbuf_get_colorspace
11643 # define gdk_pixbuf_get_has_alpha fn_gdk_pixbuf_get_has_alpha
11644 # define gdk_pixbuf_get_height fn_gdk_pixbuf_get_height
11645 # define gdk_pixbuf_get_n_channels fn_gdk_pixbuf_get_n_channels
11646 # define gdk_pixbuf_get_pixels fn_gdk_pixbuf_get_pixels
11647 # define gdk_pixbuf_get_rowstride fn_gdk_pixbuf_get_rowstride
11648 # define gdk_pixbuf_get_width fn_gdk_pixbuf_get_width
11649 # define g_error_free fn_g_error_free
11650 # define g_object_unref fn_g_object_unref
11651 # if ! GLIB_CHECK_VERSION (2, 36, 0)
11652 # define g_type_init fn_g_type_init
11653 # endif
11654 # if LIBRSVG_CHECK_VERSION (2, 52, 1)
11655 # define rsvg_handle_get_intrinsic_size_in_pixels \
11656 fn_rsvg_handle_get_intrinsic_size_in_pixels
11657 # endif
11658 # if LIBRSVG_CHECK_VERSION (2, 46, 0)
11659 # define rsvg_handle_get_intrinsic_dimensions \
11660 fn_rsvg_handle_get_intrinsic_dimensions
11661 # define rsvg_handle_get_geometry_for_layer \
11662 fn_rsvg_handle_get_geometry_for_layer
11663 # else
11664 # define rsvg_handle_get_dimensions fn_rsvg_handle_get_dimensions
11665 # endif
11666 # if LIBRSVG_CHECK_VERSION (2, 48, 0)
11667 # define rsvg_handle_set_stylesheet fn_rsvg_handle_set_stylesheet
11668 # endif
11669 # define rsvg_handle_get_pixbuf fn_rsvg_handle_get_pixbuf
11670 # if LIBRSVG_CHECK_VERSION (2, 32, 0)
11671 # define g_file_new_for_path fn_g_file_new_for_path
11672 # define g_memory_input_stream_new_from_data \
11673 fn_g_memory_input_stream_new_from_data
11674 # define rsvg_handle_new_from_stream_sync fn_rsvg_handle_new_from_stream_sync
11675 # else
11676 # define rsvg_handle_close fn_rsvg_handle_close
11677 # define rsvg_handle_new fn_rsvg_handle_new
11678 # define rsvg_handle_set_base_uri fn_rsvg_handle_set_base_uri
11679 # define rsvg_handle_write fn_rsvg_handle_write
11680 # endif
11681 # define rsvg_handle_set_dpi_x_y fn_rsvg_handle_set_dpi_x_y
11682
11683 # endif
11684
11685
11686
11687
11688 static bool
11689 svg_load (struct frame *f, struct image *img)
11690 {
11691 bool success_p = 0;
11692 Lisp_Object file_name, base_uri;
11693
11694
11695 file_name = image_spec_value (img->spec, QCfile, NULL);
11696 base_uri = image_spec_value (img->spec, QCbase_uri, NULL);
11697 if (STRINGP (file_name))
11698 {
11699 image_fd fd;
11700 Lisp_Object file = image_find_image_fd (file_name, &fd);
11701 if (!STRINGP (file))
11702 {
11703 image_error ("Cannot find image file `%s'", file_name);
11704 return 0;
11705 }
11706
11707
11708 ptrdiff_t size;
11709 char *contents = slurp_file (fd, &size);
11710 if (contents == NULL)
11711 {
11712 image_error ("Error loading SVG image `%s'", file);
11713 return 0;
11714 }
11715
11716 if (!STRINGP (base_uri))
11717 base_uri = file;
11718 success_p = svg_load_image (f, img, contents, size,
11719 SSDATA (ENCODE_FILE (base_uri)));
11720 xfree (contents);
11721 }
11722
11723
11724 else
11725 {
11726 Lisp_Object data;
11727
11728 data = image_spec_value (img->spec, QCdata, NULL);
11729 if (!STRINGP (data))
11730 {
11731 image_error ("Invalid image data `%s'", data);
11732 return 0;
11733 }
11734 if (!STRINGP (base_uri))
11735 base_uri = BVAR (current_buffer, filename);
11736 success_p = svg_load_image (f, img, SSDATA (data), SBYTES (data),
11737 (STRINGP (base_uri) ?
11738 SSDATA (ENCODE_FILE (base_uri)) : NULL));
11739 }
11740
11741 return success_p;
11742 }
11743
11744 #if LIBRSVG_CHECK_VERSION (2, 46, 0)
11745 static double
11746 svg_css_length_to_pixels (RsvgLength length, double dpi, int font_size)
11747 {
11748 double value = length.length;
11749
11750 #if ! LIBRSVG_CHECK_VERSION (2, 48, 0)
11751
11752
11753 font_size = 12;
11754 #endif
11755
11756 switch (length.unit)
11757 {
11758 case RSVG_UNIT_PX:
11759
11760 break;
11761 case RSVG_UNIT_CM:
11762
11763 value = dpi * value / 2.54;
11764 break;
11765 case RSVG_UNIT_MM:
11766
11767 value = dpi * value / 25.4;
11768 break;
11769 case RSVG_UNIT_PT:
11770
11771 value = dpi * value / 72;
11772 break;
11773 case RSVG_UNIT_PC:
11774
11775 value = dpi * value / 6;
11776 break;
11777 case RSVG_UNIT_IN:
11778 value *= dpi;
11779 break;
11780 case RSVG_UNIT_EM:
11781 value *= font_size;
11782 break;
11783 case RSVG_UNIT_EX:
11784
11785
11786 value = value * font_size / 2.0;
11787 break;
11788 case RSVG_UNIT_PERCENT:
11789
11790
11791
11792
11793
11794
11795
11796
11797
11798
11799
11800
11801 value = 0;
11802 break;
11803 default:
11804
11805 value = 0;
11806 }
11807
11808 return value;
11809 }
11810 #endif
11811
11812
11813
11814
11815
11816
11817
11818
11819 static bool
11820 svg_load_image (struct frame *f, struct image *img, char *contents,
11821 ptrdiff_t size, char *filename)
11822 {
11823 RsvgHandle *rsvg_handle;
11824 double viewbox_width, viewbox_height;
11825 GError *err = NULL;
11826 GdkPixbuf *pixbuf;
11827 int width;
11828 int height;
11829 const guint8 *pixels;
11830 int rowstride;
11831 char *wrapped_contents = NULL;
11832 ptrdiff_t wrapped_size;
11833
11834 bool empty_errmsg = true;
11835 const char *errmsg = "";
11836 ptrdiff_t errlen = 0;
11837
11838 #if LIBRSVG_CHECK_VERSION (2, 48, 0)
11839 char *css = NULL;
11840 #endif
11841
11842 #if ! GLIB_CHECK_VERSION (2, 36, 0)
11843
11844
11845 g_type_init ();
11846 #endif
11847
11848
11849
11850 #if LIBRSVG_CHECK_VERSION (2, 32, 0)
11851 GInputStream *input_stream
11852 = g_memory_input_stream_new_from_data (contents, size, NULL);
11853 GFile *base_file = filename ? g_file_new_for_path (filename) : NULL;
11854 rsvg_handle = rsvg_handle_new_from_stream_sync (input_stream, base_file,
11855 RSVG_HANDLE_FLAGS_NONE,
11856 NULL, &err);
11857
11858 if (base_file)
11859 g_object_unref (base_file);
11860 g_object_unref (input_stream);
11861
11862
11863 if (!rsvg_handle || err) goto rsvg_error;
11864
11865 rsvg_handle_set_dpi_x_y (rsvg_handle, FRAME_DISPLAY_INFO (f)->resx,
11866 FRAME_DISPLAY_INFO (f)->resy);
11867
11868 #if LIBRSVG_CHECK_VERSION (2, 48, 0)
11869 Lisp_Object lcss = image_spec_value (img->spec, QCcss, NULL);
11870 if (!STRINGP (lcss))
11871 {
11872
11873
11874
11875
11876 const char *css_spec = "svg{font-family:\"%s\";font-size:%dpx}";
11877 int css_len = strlen (css_spec) + strlen (img->face_font_family) + 1;
11878 css = xmalloc (css_len);
11879 if (css_len <= snprintf (css, css_len, css_spec,
11880 img->face_font_family, img->face_font_size))
11881 goto rsvg_error;
11882
11883 rsvg_handle_set_stylesheet (rsvg_handle, (guint8 *)css, strlen (css), NULL);
11884 }
11885 else
11886 {
11887 css = xmalloc (SBYTES (lcss) + 1);
11888 strncpy (css, SSDATA (lcss), SBYTES (lcss));
11889 *(css + SBYTES (lcss) + 1) = 0;
11890 }
11891 #endif
11892
11893 #else
11894
11895 rsvg_handle = rsvg_handle_new ();
11896 eassume (rsvg_handle);
11897
11898 rsvg_handle_set_dpi_x_y (rsvg_handle, FRAME_DISPLAY_INFO (f)->resx,
11899 FRAME_DISPLAY_INFO (f)->resy);
11900
11901
11902
11903
11904
11905 if (filename)
11906 rsvg_handle_set_base_uri (rsvg_handle, filename);
11907
11908
11909 rsvg_handle_write (rsvg_handle, (unsigned char *) contents, size, &err);
11910 if (err) goto rsvg_error;
11911
11912
11913
11914 rsvg_handle_close (rsvg_handle, &err);
11915 if (err) goto rsvg_error;
11916 #endif
11917
11918
11919 #if LIBRSVG_CHECK_VERSION (2, 46, 0)
11920 gdouble gviewbox_width = 0, gviewbox_height = 0;
11921 gboolean has_viewbox = FALSE;
11922 # if LIBRSVG_CHECK_VERSION (2, 52, 1)
11923 has_viewbox = rsvg_handle_get_intrinsic_size_in_pixels (rsvg_handle,
11924 &gviewbox_width,
11925 &gviewbox_height);
11926 # endif
11927
11928 if (has_viewbox)
11929 {
11930 viewbox_width = gviewbox_width;
11931 viewbox_height = gviewbox_height;
11932 }
11933 else
11934 {
11935 RsvgRectangle viewbox;
11936 double explicit_width = 0, explicit_height = 0;
11937
11938
11939 gboolean has_width, has_height;
11940 RsvgLength iwidth, iheight;
11941 double dpi = FRAME_DISPLAY_INFO (f)->resx;
11942
11943 rsvg_handle_get_intrinsic_dimensions (rsvg_handle,
11944 &has_width, &iwidth,
11945 &has_height, &iheight,
11946 &has_viewbox, &viewbox);
11947
11948 if (has_width)
11949 explicit_width = svg_css_length_to_pixels (iwidth, dpi,
11950 img->face_font_size);
11951 if (has_height)
11952 explicit_height = svg_css_length_to_pixels (iheight, dpi,
11953 img->face_font_size);
11954
11955 if (explicit_width > 0 && explicit_height > 0)
11956 {
11957 viewbox_width = explicit_width;
11958 viewbox_height = explicit_height;
11959 }
11960 else if (explicit_width > 0 && has_viewbox)
11961 {
11962 viewbox_width = explicit_width;
11963 viewbox_height = explicit_width * viewbox.height / viewbox.width;
11964 }
11965 else if (explicit_height > 0 && has_viewbox)
11966 {
11967 viewbox_height = explicit_height;
11968 viewbox_width = explicit_height * viewbox.width / viewbox.height;
11969 }
11970 else if (has_viewbox)
11971 {
11972 viewbox_width = viewbox.width;
11973 viewbox_height = viewbox.height;
11974 }
11975 else
11976 viewbox_width = viewbox_height = 0;
11977
11978 if (! (0 < viewbox_width && 0 < viewbox_height))
11979 {
11980
11981
11982
11983
11984
11985
11986 RsvgRectangle max_viewport_rect = {0, 0, UINT_MAX, UINT_MAX};
11987 RsvgRectangle out_logical_rect;
11988
11989 rsvg_handle_get_geometry_for_layer (rsvg_handle, NULL,
11990 &max_viewport_rect, &viewbox,
11991 &out_logical_rect, NULL);
11992 viewbox_width = viewbox.x + viewbox.width;
11993 viewbox_height = viewbox.y + viewbox.height;
11994 }
11995 }
11996 #else
11997
11998 RsvgDimensionData dimension_data;
11999 rsvg_handle_get_dimensions (rsvg_handle, &dimension_data);
12000 viewbox_width = dimension_data.width;
12001 viewbox_height = dimension_data.height;
12002 #endif
12003
12004 #ifdef HAVE_NATIVE_TRANSFORMS
12005 compute_image_size (viewbox_width, viewbox_height, img,
12006 &width, &height);
12007
12008 width = scale_image_size (width, 1, FRAME_SCALE_FACTOR (f));
12009 height = scale_image_size (height, 1, FRAME_SCALE_FACTOR (f));
12010 #else
12011 width = viewbox_width;
12012 height = viewbox_height;
12013 #endif
12014
12015 if (! check_image_size (f, width, height))
12016 {
12017 image_size_error ();
12018 goto done_error;
12019 }
12020
12021
12022 g_object_unref (rsvg_handle);
12023
12024
12025
12026
12027 {
12028 Lisp_Object value;
12029 unsigned long foreground = img->face_foreground;
12030 unsigned long background = img->face_background;
12031
12032 Lisp_Object encoded_contents
12033 = Fbase64_encode_string (make_unibyte_string (contents, size), Qt);
12034
12035
12036
12037
12038
12039
12040
12041 const char *wrapper =
12042 "<svg xmlns:xlink=\"http://www.w3.org/1999/xlink\" "
12043 "xmlns:xi=\"http://www.w3.org/2001/XInclude\" "
12044 "style=\"color: #%06X; fill: currentColor;\" "
12045 "width=\"%d\" height=\"%d\" preserveAspectRatio=\"none\" "
12046 "viewBox=\"0 0 %f %f\">"
12047 "<rect width=\"100%%\" height=\"100%%\" fill=\"#%06X\"/>"
12048 "<xi:include href=\"data:image/svg+xml;base64,%s\"></xi:include>"
12049 "</svg>";
12050
12051
12052
12053 int buffer_size = SBYTES (encoded_contents) + strlen (wrapper) + 64;
12054
12055 value = image_spec_value (img->spec, QCforeground, NULL);
12056 if (!NILP (value))
12057 foreground = image_alloc_image_color (f, img, value, img->face_foreground);
12058 value = image_spec_value (img->spec, QCbackground, NULL);
12059 if (!NILP (value))
12060 {
12061 background = image_alloc_image_color (f, img, value, img->face_background);
12062 img->background = background;
12063 img->background_valid = 1;
12064 }
12065
12066 wrapped_contents = xmalloc (buffer_size);
12067
12068 if (buffer_size <= snprintf (wrapped_contents, buffer_size, wrapper,
12069 foreground & 0xFFFFFF, width, height,
12070 viewbox_width, viewbox_height,
12071 background & 0xFFFFFF,
12072 SSDATA (encoded_contents)))
12073 goto rsvg_error;
12074
12075 wrapped_size = strlen (wrapped_contents);
12076 }
12077
12078
12079
12080 #if LIBRSVG_CHECK_VERSION (2, 32, 0)
12081 input_stream = g_memory_input_stream_new_from_data (wrapped_contents, wrapped_size, NULL);
12082 base_file = filename ? g_file_new_for_path (filename) : NULL;
12083 rsvg_handle = rsvg_handle_new_from_stream_sync (input_stream, base_file,
12084 RSVG_HANDLE_FLAGS_NONE,
12085 NULL, &err);
12086
12087 if (base_file)
12088 g_object_unref (base_file);
12089 g_object_unref (input_stream);
12090
12091
12092 if (!rsvg_handle || err) goto rsvg_error;
12093
12094 rsvg_handle_set_dpi_x_y (rsvg_handle, FRAME_DISPLAY_INFO (f)->resx,
12095 FRAME_DISPLAY_INFO (f)->resy);
12096
12097 #if LIBRSVG_CHECK_VERSION (2, 48, 0)
12098 rsvg_handle_set_stylesheet (rsvg_handle, (guint8 *)css, strlen (css), NULL);
12099 #endif
12100 #else
12101
12102 rsvg_handle = rsvg_handle_new ();
12103 eassume (rsvg_handle);
12104
12105 rsvg_handle_set_dpi_x_y (rsvg_handle, FRAME_DISPLAY_INFO (f)->resx,
12106 FRAME_DISPLAY_INFO (f)->resy);
12107
12108
12109
12110
12111
12112 if (filename)
12113 rsvg_handle_set_base_uri (rsvg_handle, filename);
12114
12115
12116 rsvg_handle_write (rsvg_handle, (unsigned char *) wrapped_contents, wrapped_size, &err);
12117 if (err) goto rsvg_error;
12118
12119
12120
12121 rsvg_handle_close (rsvg_handle, &err);
12122 if (err) goto rsvg_error;
12123 #endif
12124
12125
12126
12127
12128 pixbuf = rsvg_handle_get_pixbuf (rsvg_handle);
12129 if (!pixbuf) goto rsvg_error;
12130 g_object_unref (rsvg_handle);
12131 xfree (wrapped_contents);
12132
12133 #if LIBRSVG_CHECK_VERSION (2, 48, 0)
12134 if (!STRINGP (lcss))
12135 xfree (css);
12136 #endif
12137
12138
12139 width = gdk_pixbuf_get_width (pixbuf);
12140 height = gdk_pixbuf_get_height (pixbuf);
12141 pixels = gdk_pixbuf_get_pixels (pixbuf);
12142 rowstride = gdk_pixbuf_get_rowstride (pixbuf);
12143
12144
12145 eassert (gdk_pixbuf_get_colorspace (pixbuf) == GDK_COLORSPACE_RGB);
12146 eassert (gdk_pixbuf_get_n_channels (pixbuf) == 4);
12147 eassert (gdk_pixbuf_get_has_alpha (pixbuf));
12148 eassert (gdk_pixbuf_get_bits_per_sample (pixbuf) == 8);
12149
12150 {
12151
12152 Emacs_Pix_Container ximg;
12153 if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, 0))
12154 {
12155 g_object_unref (pixbuf);
12156 return false;
12157 }
12158
12159 init_color_table ();
12160
12161
12162
12163
12164
12165 for (int y = 0; y < height; ++y)
12166 {
12167 for (int x = 0; x < width; ++x)
12168 {
12169 int red = *pixels++;
12170 int green = *pixels++;
12171 int blue = *pixels++;
12172
12173
12174 pixels++;
12175
12176 PUT_PIXEL (ximg, x, y, lookup_rgb_color (f, red << 8, green << 8, blue << 8));
12177 }
12178
12179 pixels += rowstride - 4 * width;
12180 }
12181
12182 #ifdef COLOR_TABLE_SUPPORT
12183
12184 img->colors = colors_in_color_table (&img->ncolors);
12185 free_color_table ();
12186 #endif
12187
12188 g_object_unref (pixbuf);
12189
12190 img->width = width;
12191 img->height = height;
12192
12193
12194
12195 IMAGE_BACKGROUND (img, f, (Emacs_Pix_Context)ximg);
12196
12197
12198 image_put_x_image (f, img, ximg, 0);
12199 }
12200
12201 eassume (err == NULL);
12202 return true;
12203
12204 rsvg_error:
12205 if (err && err->message[0])
12206 {
12207 errmsg = err->message;
12208 errlen = strlen (errmsg);
12209
12210
12211 while (errlen && c_isspace (errmsg[errlen - 1]))
12212 errlen--;
12213 empty_errmsg = errlen == 0;
12214 }
12215
12216 if (empty_errmsg)
12217 image_error ("Error parsing SVG image");
12218 else
12219 image_error ("Error parsing SVG image: %s", make_string (errmsg, errlen));
12220
12221 if (err)
12222 g_error_free (err);
12223
12224 done_error:
12225 if (rsvg_handle)
12226 g_object_unref (rsvg_handle);
12227 if (wrapped_contents)
12228 xfree (wrapped_contents);
12229 #if LIBRSVG_CHECK_VERSION (2, 48, 0)
12230 if (css && !STRINGP (lcss))
12231 xfree (css);
12232 #endif
12233 return false;
12234 }
12235
12236 #endif
12237
12238
12239
12240
12241
12242
12243
12244
12245 #if defined HAVE_X_WINDOWS && !defined USE_CAIRO
12246 #define HAVE_GHOSTSCRIPT 1
12247 #endif
12248
12249 #ifdef HAVE_GHOSTSCRIPT
12250
12251
12252
12253 enum gs_keyword_index
12254 {
12255 GS_TYPE,
12256 GS_PT_WIDTH,
12257 GS_PT_HEIGHT,
12258 GS_FILE,
12259 GS_LOADER,
12260 GS_BOUNDING_BOX,
12261 GS_ASCENT,
12262 GS_MARGIN,
12263 GS_RELIEF,
12264 GS_ALGORITHM,
12265 GS_HEURISTIC_MASK,
12266 GS_MASK,
12267 GS_BACKGROUND,
12268 GS_LAST
12269 };
12270
12271
12272
12273
12274 static const struct image_keyword gs_format[GS_LAST] =
12275 {
12276 {":type", IMAGE_SYMBOL_VALUE, 1},
12277 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
12278 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
12279 {":file", IMAGE_STRING_VALUE, 1},
12280 {":loader", IMAGE_FUNCTION_VALUE, 0},
12281 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
12282 {":ascent", IMAGE_ASCENT_VALUE, 0},
12283 {":margin", IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR, 0},
12284 {":relief", IMAGE_INTEGER_VALUE, 0},
12285 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12286 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12287 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12288 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
12289 };
12290
12291
12292
12293
12294 static bool
12295 gs_image_p (Lisp_Object object)
12296 {
12297 struct image_keyword fmt[GS_LAST];
12298 Lisp_Object tem;
12299 int i;
12300
12301 memcpy (fmt, gs_format, sizeof fmt);
12302
12303 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript))
12304 return 0;
12305
12306
12307 tem = fmt[GS_BOUNDING_BOX].value;
12308 if (CONSP (tem))
12309 {
12310 for (i = 0; i < 4; ++i, tem = XCDR (tem))
12311 if (!CONSP (tem) || !FIXNUMP (XCAR (tem)))
12312 return 0;
12313 if (!NILP (tem))
12314 return 0;
12315 }
12316 else if (VECTORP (tem))
12317 {
12318 if (ASIZE (tem) != 4)
12319 return 0;
12320 for (i = 0; i < 4; ++i)
12321 if (!FIXNUMP (AREF (tem, i)))
12322 return 0;
12323 }
12324 else
12325 return 0;
12326
12327 return 1;
12328 }
12329
12330
12331
12332
12333
12334 static bool
12335 gs_load (struct frame *f, struct image *img)
12336 {
12337 uintmax_t printnum1, printnum2;
12338 char buffer[sizeof " " + 2 * INT_STRLEN_BOUND (intmax_t)];
12339 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
12340 Lisp_Object frame;
12341 double in_width, in_height;
12342 Lisp_Object pixel_colors = Qnil;
12343
12344
12345
12346
12347
12348 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
12349 in_width = FIXNUMP (pt_width) ? XFIXNAT (pt_width) / 72.0 : 0;
12350 in_width *= FRAME_RES_X (f);
12351 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
12352 in_height = FIXNUMP (pt_height) ? XFIXNAT (pt_height) / 72.0 : 0;
12353 in_height *= FRAME_RES_Y (f);
12354
12355 if (! (in_width <= INT_MAX && in_height <= INT_MAX
12356 && check_image_size (f, in_width, in_height)))
12357 {
12358 image_size_error ();
12359 return 0;
12360 }
12361 img->width = in_width;
12362 img->height = in_height;
12363
12364
12365 eassert (img->pixmap == NO_PIXMAP);
12366
12367 if (image_check_image_size (0, img->width, img->height))
12368 {
12369
12370 block_input ();
12371 img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f),
12372 img->width, img->height,
12373 FRAME_DISPLAY_INFO (f)->n_planes);
12374 unblock_input ();
12375 }
12376
12377 if (!img->pixmap)
12378 {
12379 image_error ("Unable to create pixmap for `%s'" , img->spec);
12380 return 0;
12381 }
12382
12383
12384
12385
12386
12387 printnum1 = FRAME_X_DRAWABLE (f);
12388 printnum2 = img->pixmap;
12389 window_and_pixmap_id
12390 = make_formatted_string (buffer, "%"PRIuMAX" %"PRIuMAX,
12391 printnum1, printnum2);
12392
12393 printnum1 = FRAME_FOREGROUND_PIXEL (f);
12394 printnum2 = FRAME_BACKGROUND_PIXEL (f);
12395 pixel_colors
12396 = make_formatted_string (buffer, "%"PRIuMAX" %"PRIuMAX,
12397 printnum1, printnum2);
12398
12399 XSETFRAME (frame, f);
12400 loader = image_spec_value (img->spec, QCloader, NULL);
12401 if (NILP (loader))
12402 loader = intern ("gs-load-image");
12403
12404 img->lisp_data = call6 (loader, frame, img->spec,
12405 make_fixnum (img->width),
12406 make_fixnum (img->height),
12407 window_and_pixmap_id,
12408 pixel_colors);
12409 return PROCESSP (img->lisp_data);
12410 }
12411
12412
12413
12414
12415
12416
12417 void
12418 x_kill_gs_process (Pixmap pixmap, struct frame *f)
12419 {
12420 struct image_cache *c = FRAME_IMAGE_CACHE (f);
12421 ptrdiff_t i;
12422 struct image *img;
12423
12424
12425 for (i = 0; i < c->used; ++i)
12426 if (c->images[i]->pixmap == pixmap)
12427 break;
12428
12429
12430
12431 if (i == c->used)
12432 return;
12433
12434
12435
12436 img = c->images[i];
12437 eassert (PROCESSP (img->lisp_data));
12438 Fkill_process (img->lisp_data, Qnil);
12439 img->lisp_data = Qnil;
12440
12441 #if defined (HAVE_X_WINDOWS)
12442
12443
12444
12445
12446 if (x_mutable_colormap (FRAME_X_VISUAL_INFO (f)))
12447 {
12448 XImage *ximg;
12449
12450 block_input ();
12451
12452
12453 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
12454 0, 0, img->width, img->height, ~0, ZPixmap);
12455 if (ximg)
12456 {
12457
12458 init_color_table ();
12459
12460
12461
12462
12463 #ifdef COLOR_TABLE_SUPPORT
12464 for (int y = 0; y < img->height; ++y)
12465 for (int x = 0; x < img->width; ++x)
12466 {
12467 unsigned long pixel = XGetPixel (ximg, x, y);
12468
12469 lookup_pixel_color (f, pixel);
12470 }
12471
12472
12473 img->colors = colors_in_color_table (&img->ncolors);
12474 free_color_table ();
12475 #endif
12476 XDestroyImage (ximg);
12477 }
12478 else
12479 image_error ("Cannot get X image of `%s'; colors will not be freed",
12480 img->spec);
12481
12482 unblock_input ();
12483 }
12484 #endif
12485
12486
12487
12488 block_input ();
12489 postprocess_image (f, img);
12490 unblock_input ();
12491 }
12492
12493 #endif
12494
12495
12496
12497
12498
12499 DEFUN ("imagep", Fimagep, Simagep, 1, 1, 0,
12500 doc: )
12501 (Lisp_Object spec)
12502 {
12503 return valid_image_p (spec) ? Qt : Qnil;
12504 }
12505
12506 #ifdef GLYPH_DEBUG
12507
12508 DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0,
12509 doc: )
12510 (Lisp_Object spec)
12511 {
12512 ptrdiff_t id = -1;
12513
12514 if (valid_image_p (spec))
12515 id = lookup_image (SELECTED_FRAME (), spec, -1);
12516
12517 debug_print (spec);
12518 return make_fixnum (id);
12519 }
12520
12521 #endif
12522
12523
12524
12525
12526
12527
12528 DEFUN ("image-transforms-p", Fimage_transforms_p, Simage_transforms_p, 0, 1, 0,
12529 doc:
12530
12531
12532
12533
12534
12535
12536 )
12537 (Lisp_Object frame)
12538 {
12539 struct frame *f = decode_live_frame (frame);
12540 if (FRAME_WINDOW_P (f))
12541 {
12542 #ifdef HAVE_NATIVE_TRANSFORMS
12543 # if defined HAVE_IMAGEMAGICK || defined (USE_CAIRO) || defined (HAVE_NS) \
12544 || defined (HAVE_HAIKU) | defined HAVE_ANDROID
12545 return list2 (Qscale, Qrotate90);
12546 # elif defined (HAVE_X_WINDOWS) && defined (HAVE_XRENDER)
12547 if (FRAME_DISPLAY_INFO (f)->xrender_supported_p)
12548 return list2 (Qscale, Qrotate90);
12549 # elif defined (HAVE_NTGUI)
12550 return (w32_image_rotations_p ()
12551 ? list2 (Qscale, Qrotate90)
12552 : list1 (Qscale));
12553 # endif
12554 #endif
12555 }
12556
12557 return Qnil;
12558 }
12559
12560 DEFUN ("image-cache-size", Fimage_cache_size, Simage_cache_size, 0, 0, 0,
12561 doc: )
12562 (void)
12563 {
12564 Lisp_Object tail, frame;
12565 size_t total = 0;
12566
12567 FOR_EACH_FRAME (tail, frame)
12568 if (FRAME_WINDOW_P (XFRAME (frame)))
12569 total += image_frame_cache_size (XFRAME (frame));
12570
12571 #if defined (HAVE_WEBP) || defined (HAVE_GIF)
12572 struct anim_cache *pcache = anim_cache;
12573 while (pcache)
12574 {
12575 total += pcache->byte_size;
12576 pcache = pcache->next;
12577 }
12578 #endif
12579
12580 return make_int (total);
12581 }
12582
12583
12584 DEFUN ("init-image-library", Finit_image_library, Sinit_image_library, 1, 1, 0,
12585 doc:
12586
12587
12588
12589
12590 )
12591 (Lisp_Object type)
12592 {
12593 return lookup_image_type (type) ? Qt : Qnil;
12594 }
12595
12596 static bool
12597 initialize_image_type (struct image_type const *type)
12598 {
12599 #ifdef WINDOWSNT
12600 Lisp_Object typesym = builtin_lisp_symbol (type->type);
12601
12602 # if HAVE_NATIVE_IMAGE_API
12603 if (image_can_use_native_api (typesym))
12604 return true;
12605 # endif
12606
12607 Lisp_Object tested = Fassq (typesym, Vlibrary_cache);
12608
12609 if (CONSP (tested))
12610 return !NILP (XCDR (tested)) ? true : false;
12611
12612 bool (*init) (void) = type->init;
12613 if (init)
12614 {
12615 bool type_valid = init ();
12616 Vlibrary_cache = Fcons (Fcons (typesym, type_valid ? Qt : Qnil),
12617 Vlibrary_cache);
12618 return type_valid;
12619 }
12620 #endif
12621 return true;
12622 }
12623
12624
12625
12626 static struct image_type const image_types[] =
12627 {
12628 #ifdef HAVE_GHOSTSCRIPT
12629 { SYMBOL_INDEX (Qpostscript), gs_image_p, gs_load, image_clear_image },
12630 #endif
12631 #ifdef HAVE_IMAGEMAGICK
12632 { SYMBOL_INDEX (Qimagemagick), imagemagick_image_p, imagemagick_load,
12633 imagemagick_clear_image },
12634 #endif
12635 #ifdef HAVE_RSVG
12636 { SYMBOL_INDEX (Qsvg), svg_image_p, svg_load, image_clear_image,
12637 IMAGE_TYPE_INIT (init_svg_functions) },
12638 #endif
12639 #if defined HAVE_PNG
12640 { SYMBOL_INDEX (Qpng), png_image_p, png_load, image_clear_image,
12641 IMAGE_TYPE_INIT (init_png_functions) },
12642 #endif
12643 #if defined HAVE_GIF
12644 { SYMBOL_INDEX (Qgif), gif_image_p, gif_load, gif_clear_image,
12645 IMAGE_TYPE_INIT (init_gif_functions) },
12646 #endif
12647 #if defined HAVE_TIFF
12648 { SYMBOL_INDEX (Qtiff), tiff_image_p, tiff_load, image_clear_image,
12649 IMAGE_TYPE_INIT (init_tiff_functions) },
12650 #endif
12651 #if defined HAVE_JPEG
12652 { SYMBOL_INDEX (Qjpeg), jpeg_image_p, jpeg_load, image_clear_image,
12653 IMAGE_TYPE_INIT (init_jpeg_functions) },
12654 #endif
12655 #if defined HAVE_XPM || defined HAVE_NS || defined HAVE_HAIKU \
12656 || defined HAVE_PGTK || defined HAVE_ANDROID
12657 { SYMBOL_INDEX (Qxpm), xpm_image_p, xpm_load, image_clear_image,
12658 IMAGE_TYPE_INIT (init_xpm_functions) },
12659 #endif
12660 #if defined HAVE_WEBP
12661 { SYMBOL_INDEX (Qwebp), webp_image_p, webp_load, image_clear_image,
12662 IMAGE_TYPE_INIT (init_webp_functions) },
12663 #endif
12664 { SYMBOL_INDEX (Qxbm), xbm_image_p, xbm_load, image_clear_image },
12665 { SYMBOL_INDEX (Qpbm), pbm_image_p, pbm_load, image_clear_image },
12666 };
12667
12668 #if HAVE_NATIVE_IMAGE_API
12669 struct image_type native_image_type =
12670 { SYMBOL_INDEX (Qnative_image), native_image_p, native_image_load,
12671 image_clear_image };
12672 #endif
12673
12674
12675
12676
12677 static struct image_type const *
12678 lookup_image_type (Lisp_Object type)
12679 {
12680 #if HAVE_NATIVE_IMAGE_API
12681 if (image_can_use_native_api (type))
12682 return &native_image_type;
12683 #endif
12684
12685 for (int i = 0; i < ARRAYELTS (image_types); i++)
12686 {
12687 struct image_type const *r = &image_types[i];
12688 if (EQ (type, builtin_lisp_symbol (r->type)))
12689 return initialize_image_type (r) ? r : NULL;
12690 }
12691 return NULL;
12692 }
12693
12694
12695
12696 void
12697 image_prune_animation_caches (bool clear)
12698 {
12699 #if defined (HAVE_WEBP) || defined (HAVE_GIF)
12700 anim_prune_animation_cache (clear? Qt: Qnil);
12701 #endif
12702 #ifdef HAVE_IMAGEMAGICK
12703 imagemagick_prune_animation_cache (clear);
12704 #endif
12705 }
12706
12707 void
12708 syms_of_image (void)
12709 {
12710
12711
12712 DEFVAR_LISP ("image-types", Vimage_types,
12713 doc:
12714
12715 );
12716 Vimage_types = Qnil;
12717
12718 DEFVAR_LISP ("max-image-size", Vmax_image_size,
12719 doc:
12720
12721
12722
12723
12724
12725
12726
12727 );
12728 Vmax_image_size = make_float (MAX_IMAGE_SIZE);
12729
12730
12731 DEFSYM (Qcount, "count");
12732 DEFSYM (Qextension_data, "extension-data");
12733 DEFSYM (Qdelay, "delay");
12734
12735
12736 DEFSYM (QCascent, ":ascent");
12737 DEFSYM (QCmargin, ":margin");
12738 DEFSYM (QCrelief, ":relief");
12739 DEFSYM (QCconversion, ":conversion");
12740 DEFSYM (QCcolor_symbols, ":color-symbols");
12741 DEFSYM (QCheuristic_mask, ":heuristic-mask");
12742 DEFSYM (QCindex, ":index");
12743 DEFSYM (QCcrop, ":crop");
12744 DEFSYM (QCrotation, ":rotation");
12745 DEFSYM (QCmatrix, ":matrix");
12746 DEFSYM (QCscale, ":scale");
12747 DEFSYM (QCtransform_smoothing, ":transform-smoothing");
12748 DEFSYM (QCcolor_adjustment, ":color-adjustment");
12749 DEFSYM (QCmask, ":mask");
12750 DEFSYM (QCflip, ":flip");
12751
12752
12753 DEFSYM (Qlaplace, "laplace");
12754 DEFSYM (Qemboss, "emboss");
12755 DEFSYM (Qedge_detection, "edge-detection");
12756 DEFSYM (Qheuristic, "heuristic");
12757
12758 DEFSYM (Qpostscript, "postscript");
12759 DEFSYM (QCmax_width, ":max-width");
12760 DEFSYM (QCmax_height, ":max-height");
12761
12762 DEFSYM (Qem, "em");
12763
12764 #ifdef HAVE_NATIVE_TRANSFORMS
12765 DEFSYM (Qscale, "scale");
12766 DEFSYM (Qrotate, "rotate");
12767 DEFSYM (Qrotate90, "rotate90");
12768 DEFSYM (Qcrop, "crop");
12769 #endif
12770
12771 #ifdef HAVE_GHOSTSCRIPT
12772 add_image_type (Qpostscript);
12773 DEFSYM (QCloader, ":loader");
12774 DEFSYM (QCpt_width, ":pt-width");
12775 DEFSYM (QCpt_height, ":pt-height");
12776 #endif
12777
12778 #ifdef HAVE_NTGUI
12779
12780
12781
12782
12783 DEFSYM (Qlibpng_version, "libpng-version");
12784 Fset (Qlibpng_version,
12785 #if HAVE_PNG
12786 make_fixnum (PNG_LIBPNG_VER)
12787 #else
12788 make_fixnum (-1)
12789 #endif
12790 );
12791 DEFSYM (Qlibgif_version, "libgif-version");
12792 Fset (Qlibgif_version,
12793 #ifdef HAVE_GIF
12794 make_fixnum (GIFLIB_MAJOR * 10000
12795 + GIFLIB_MINOR * 100
12796 + GIFLIB_RELEASE)
12797 #else
12798 make_fixnum (-1)
12799 #endif
12800 );
12801 DEFSYM (Qlibjpeg_version, "libjpeg-version");
12802 Fset (Qlibjpeg_version,
12803 #if HAVE_JPEG
12804 make_fixnum (JPEG_LIB_VERSION)
12805 #else
12806 make_fixnum (-1)
12807 #endif
12808 );
12809 #endif
12810
12811 DEFSYM (Qpbm, "pbm");
12812 add_image_type (Qpbm);
12813
12814 DEFSYM (Qxbm, "xbm");
12815 add_image_type (Qxbm);
12816
12817 #if defined (HAVE_XPM) || defined (HAVE_NS) \
12818 || defined (HAVE_HAIKU) || defined (HAVE_PGTK) \
12819 || defined (HAVE_ANDROID)
12820 DEFSYM (Qxpm, "xpm");
12821 add_image_type (Qxpm);
12822 #endif
12823
12824 #if defined (HAVE_JPEG) || defined (HAVE_NATIVE_IMAGE_API)
12825 DEFSYM (Qjpeg, "jpeg");
12826 add_image_type (Qjpeg);
12827 #endif
12828
12829 #if defined (HAVE_TIFF) || defined (HAVE_NATIVE_IMAGE_API)
12830 DEFSYM (Qtiff, "tiff");
12831 add_image_type (Qtiff);
12832 #endif
12833
12834 #if defined (HAVE_GIF) || defined (HAVE_NATIVE_IMAGE_API)
12835 DEFSYM (Qgif, "gif");
12836 add_image_type (Qgif);
12837 #endif
12838
12839 #if defined (HAVE_PNG) || defined (HAVE_NATIVE_IMAGE_API)
12840 DEFSYM (Qpng, "png");
12841 add_image_type (Qpng);
12842 #endif
12843
12844 #if defined (HAVE_WEBP) \
12845 || (defined (HAVE_NATIVE_IMAGE_API) \
12846 && ((defined (HAVE_NS) && defined (NS_IMPL_COCOA)) \
12847 || defined (HAVE_HAIKU)))
12848 DEFSYM (Qwebp, "webp");
12849 DEFSYM (Qwebpdemux, "webpdemux");
12850 add_image_type (Qwebp);
12851 #endif
12852
12853 #if defined (HAVE_IMAGEMAGICK)
12854 DEFSYM (Qimagemagick, "imagemagick");
12855 add_image_type (Qimagemagick);
12856 #endif
12857
12858 #if defined (HAVE_RSVG)
12859 DEFSYM (Qsvg, "svg");
12860 DEFSYM (QCbase_uri, ":base-uri");
12861 DEFSYM (QCcss, ":css");
12862 add_image_type (Qsvg);
12863 #ifdef HAVE_NTGUI
12864
12865 DEFSYM (Qgdk_pixbuf, "gdk-pixbuf");
12866 DEFSYM (Qglib, "glib");
12867 # if LIBRSVG_CHECK_VERSION (2, 32, 0)
12868 DEFSYM (Qgio, "gio");
12869 # endif
12870 DEFSYM (Qgobject, "gobject");
12871 #endif
12872 #elif defined HAVE_NATIVE_IMAGE_API \
12873 && ((defined HAVE_NS && defined NS_IMPL_COCOA) \
12874 || defined HAVE_HAIKU)
12875 DEFSYM (Qsvg, "svg");
12876
12877
12878 if (image_can_use_native_api (Qsvg))
12879 add_image_type (Qsvg);
12880 #endif
12881
12882 #ifdef HAVE_NS
12883 DEFSYM (Qheic, "heic");
12884 add_image_type (Qheic);
12885 #endif
12886
12887 #if HAVE_NATIVE_IMAGE_API
12888 DEFSYM (Qnative_image, "native-image");
12889
12890 # if defined HAVE_NTGUI || defined HAVE_HAIKU
12891 DEFSYM (Qbmp, "bmp");
12892 add_image_type (Qbmp);
12893 # endif
12894
12895 # ifdef HAVE_NTGUI
12896 DEFSYM (Qgdiplus, "gdiplus");
12897 DEFSYM (Qshlwapi, "shlwapi");
12898 # endif
12899 #endif
12900
12901 defsubr (&Sinit_image_library);
12902 #ifdef HAVE_IMAGEMAGICK
12903 defsubr (&Simagemagick_types);
12904 #endif
12905 defsubr (&Sclear_image_cache);
12906 defsubr (&Simage_flush);
12907 defsubr (&Simage_size);
12908 defsubr (&Simage_mask_p);
12909 defsubr (&Simage_metadata);
12910 defsubr (&Simage_cache_size);
12911 defsubr (&Simagep);
12912
12913 #ifdef GLYPH_DEBUG
12914 defsubr (&Slookup_image);
12915 #endif
12916
12917 DEFSYM (QCanimate_buffer, ":animate-buffer");
12918 DEFSYM (QCanimate_tardiness, ":animate-tardiness");
12919 DEFSYM (QCanimate_position, ":animate-position");
12920 DEFSYM (QCanimate_multi_frame_data, ":animate-multi-frame-data");
12921
12922 defsubr (&Simage_transforms_p);
12923
12924 DEFVAR_BOOL ("cross-disabled-images", cross_disabled_images,
12925 doc:
12926
12927 );
12928 cross_disabled_images = 0;
12929
12930 DEFVAR_LISP ("x-bitmap-file-path", Vx_bitmap_file_path,
12931 doc: );
12932 Vx_bitmap_file_path = decode_env_path (0, PATH_BITMAPS, 0);
12933
12934 DEFVAR_LISP ("image-cache-eviction-delay", Vimage_cache_eviction_delay,
12935 doc:
12936
12937
12938
12939
12940
12941 );
12942 Vimage_cache_eviction_delay = make_fixnum (300);
12943 #ifdef HAVE_IMAGEMAGICK
12944 DEFVAR_INT ("imagemagick-render-type", imagemagick_render_type,
12945 doc:
12946
12947
12948
12949
12950
12951
12952 );
12953
12954 imagemagick_render_type = 0;
12955 #endif
12956 }