* nsterm.m (ns_confirm_quit): New variable.
[bpt/emacs.git] / src / image.c
CommitLineData
4ef0d4d0 1/* Functions for image support on window system.
0b5538bd 2 Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
76b6f707 3 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
6678dc11 4 Free Software Foundation, Inc.
4ef0d4d0
KS
5
6This file is part of GNU Emacs.
7
9ec0b715 8GNU Emacs is free software: you can redistribute it and/or modify
4ef0d4d0 9it under the terms of the GNU General Public License as published by
9ec0b715
GM
10the Free Software Foundation, either version 3 of the License, or
11(at your option) any later version.
4ef0d4d0
KS
12
13GNU Emacs is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
9ec0b715 19along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
4ef0d4d0
KS
20
21#include <config.h>
4ef0d4d0
KS
22#include <stdio.h>
23#include <math.h>
be8c4ce4 24#include <ctype.h>
4ef0d4d0
KS
25
26#ifdef HAVE_UNISTD_H
27#include <unistd.h>
28#endif
29
30/* This makes the fields of a Display accessible, in Xlib header files. */
31
32#define XLIB_ILLEGAL_ACCESS
33
34#include "lisp.h"
35#include "frame.h"
36#include "window.h"
37#include "dispextern.h"
38#include "blockinput.h"
39#include "systime.h"
40#include <epaths.h>
3dcc8b84 41#include "character.h"
022af124 42#include "coding.h"
6087292e 43#include "termhooks.h"
3dcc8b84 44#include "font.h"
4ef0d4d0
KS
45
46#ifdef HAVE_X_WINDOWS
47#include "xterm.h"
48#include <sys/types.h>
49#include <sys/stat.h>
50
51#define COLOR_TABLE_SUPPORT 1
52
53typedef struct x_bitmap_record Bitmap_Record;
4ef0d4d0
KS
54#define GET_PIXEL(ximg, x, y) XGetPixel(ximg, x, y)
55#define NO_PIXMAP None
4ef0d4d0
KS
56
57#define RGB_PIXEL_COLOR unsigned long
58
9ecf6403
YM
59#define PIX_MASK_RETAIN 0
60#define PIX_MASK_DRAW 1
4ef0d4d0
KS
61#endif /* HAVE_X_WINDOWS */
62
63
64#ifdef HAVE_NTGUI
65#include "w32term.h"
66
67/* W32_TODO : Color tables on W32. */
68#undef COLOR_TABLE_SUPPORT
69
70typedef struct w32_bitmap_record Bitmap_Record;
4ef0d4d0
KS
71#define GET_PIXEL(ximg, x, y) GetPixel(ximg, x, y)
72#define NO_PIXMAP 0
4ef0d4d0
KS
73
74#define RGB_PIXEL_COLOR COLORREF
75
9ecf6403
YM
76#define PIX_MASK_RETAIN 0
77#define PIX_MASK_DRAW 1
4ef0d4d0
KS
78
79#define FRAME_X_VISUAL(f) FRAME_X_DISPLAY_INFO (f)->visual
80#define x_defined_color w32_defined_color
81#define DefaultDepthOfScreen(screen) (one_w32_display_info.n_cbits)
8b7d0a16
JR
82
83/* Functions from w32term.c that depend on XColor (so can't go in w32term.h
84 without modifying lots of files). */
85extern void x_query_colors (struct frame *f, XColor *colors, int ncolors);
86extern void x_query_color (struct frame *f, XColor *color);
4ef0d4d0
KS
87#endif /* HAVE_NTGUI */
88
edfda783
AR
89#ifdef HAVE_NS
90#include "nsterm.h"
91#include <sys/types.h>
92#include <sys/stat.h>
93
94#undef COLOR_TABLE_SUPPORT
95
96typedef struct ns_bitmap_record Bitmap_Record;
97
98#define GET_PIXEL(ximg, x, y) XGetPixel(ximg, x, y)
99#define NO_PIXMAP 0
100
101#define RGB_PIXEL_COLOR unsigned long
102#define ZPixmap 0
103
104#define PIX_MASK_RETAIN 0
105#define PIX_MASK_DRAW 1
106
107#define FRAME_X_VISUAL FRAME_NS_DISPLAY_INFO(f)->visual
108#define x_defined_color(f, name, color_def, alloc) \
109 ns_defined_color (f, name, color_def, alloc, 0)
110#define FRAME_X_SCREEN(f) 0
9e50ff0c 111#define DefaultDepthOfScreen(screen) x_display_list->n_planes
edfda783
AR
112#endif /* HAVE_NS */
113
114
4ef0d4d0
KS
115/* Search path for bitmap files. */
116
117Lisp_Object Vx_bitmap_file_path;
118
119
120static void x_disable_image P_ ((struct frame *, struct image *));
121static void x_edge_detection P_ ((struct frame *, struct image *, Lisp_Object,
122 Lisp_Object));
123
124static void init_color_table P_ ((void));
125static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
126#ifdef COLOR_TABLE_SUPPORT
127static void free_color_table P_ ((void));
128static unsigned long *colors_in_color_table P_ ((int *n));
129static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
130#endif
131
132/* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
133 id, which is just an int that this section returns. Bitmaps are
134 reference counted so they can be shared among frames.
135
136 Bitmap indices are guaranteed to be > 0, so a negative number can
137 be used to indicate no bitmap.
138
139 If you use x_create_bitmap_from_data, then you must keep track of
140 the bitmaps yourself. That is, creating a bitmap from the same
141 data more than once will not be caught. */
142
143#ifdef MAC_OS
144
145static XImagePtr
146XGetImage (display, pixmap, x, y, width, height, plane_mask, format)
147 Display *display; /* not used */
148 Pixmap pixmap;
149 int x, y; /* not used */
150 unsigned int width, height; /* not used */
151 unsigned long plane_mask; /* not used */
152 int format; /* not used */
153{
2ff0845e 154#if !USE_MAC_IMAGE_IO
4ef0d4d0
KS
155#if GLYPH_DEBUG
156 xassert (x == 0 && y == 0);
157 {
158 Rect ri, rp;
159 SetRect (&ri, 0, 0, width, height);
160 xassert (EqualRect (&ri, GetPixBounds (GetGWorldPixMap (pixmap), &rp)));
161 }
162 xassert (! (pixelsLocked & GetPixelsState (GetGWorldPixMap (pixmap))));
163#endif
164
165 LockPixels (GetGWorldPixMap (pixmap));
2ff0845e 166#endif
4ef0d4d0
KS
167
168 return pixmap;
169}
170
171static void
172XPutPixel (ximage, x, y, pixel)
173 XImagePtr ximage;
174 int x, y;
175 unsigned long pixel;
176{
2ff0845e
YM
177#if USE_MAC_IMAGE_IO
178 if (ximage->bits_per_pixel == 32)
179 ((unsigned int *)(ximage->data + y * ximage->bytes_per_line))[x] = pixel;
180 else
181 ((unsigned char *)(ximage->data + y * ximage->bytes_per_line))[x] = pixel;
182#else
9ecf6403
YM
183 PixMapHandle pixmap = GetGWorldPixMap (ximage);
184 short depth = GetPixDepth (pixmap);
185
c7fea325 186#if defined (WORDS_BIG_ENDIAN) || !USE_CG_DRAWING
9ecf6403
YM
187 if (depth == 32)
188 {
189 char *base_addr = GetPixBaseAddr (pixmap);
190 short row_bytes = GetPixRowBytes (pixmap);
191
4cdffedf 192 ((unsigned long *) (base_addr + y * row_bytes))[x] = 0xff000000 | pixel;
9ecf6403 193 }
c7fea325
YM
194 else
195#endif
1caa0b53 196 if (depth == 1)
9ecf6403
YM
197 {
198 char *base_addr = GetPixBaseAddr (pixmap);
199 short row_bytes = GetPixRowBytes (pixmap);
200
201 if (pixel == PIX_MASK_DRAW)
202 base_addr[y * row_bytes + x / 8] |= (1 << 7) >> (x & 7);
203 else
204 base_addr[y * row_bytes + x / 8] &= ~((1 << 7) >> (x & 7));
205 }
206 else
207 {
208 CGrafPtr old_port;
209 GDHandle old_gdh;
210 RGBColor color;
211
212 GetGWorld (&old_port, &old_gdh);
213 SetGWorld (ximage, NULL);
4ef0d4d0 214
9ecf6403
YM
215 color.red = RED16_FROM_ULONG (pixel);
216 color.green = GREEN16_FROM_ULONG (pixel);
217 color.blue = BLUE16_FROM_ULONG (pixel);
4ef0d4d0 218
9ecf6403 219 SetCPixel (x, y, &color);
2a316a84 220
9ecf6403
YM
221 SetGWorld (old_port, old_gdh);
222 }
2ff0845e 223#endif
4ef0d4d0
KS
224}
225
226static unsigned long
227XGetPixel (ximage, x, y)
228 XImagePtr ximage;
229 int x, y;
230{
2ff0845e
YM
231#if USE_MAC_IMAGE_IO
232 if (ximage->bits_per_pixel == 32)
233 return ((unsigned int *)(ximage->data + y * ximage->bytes_per_line))[x];
234 else
235 return ((unsigned char *)(ximage->data + y * ximage->bytes_per_line))[x];
236#else
9ecf6403
YM
237 PixMapHandle pixmap = GetGWorldPixMap (ximage);
238 short depth = GetPixDepth (pixmap);
4ef0d4d0 239
c7fea325 240#if defined (WORDS_BIG_ENDIAN) || !USE_CG_DRAWING
9ecf6403
YM
241 if (depth == 32)
242 {
243 char *base_addr = GetPixBaseAddr (pixmap);
244 short row_bytes = GetPixRowBytes (pixmap);
245
4cdffedf 246 return ((unsigned long *) (base_addr + y * row_bytes))[x] & 0x00ffffff;
9ecf6403 247 }
c7fea325
YM
248 else
249#endif
250 if (depth == 1)
9ecf6403
YM
251 {
252 char *base_addr = GetPixBaseAddr (pixmap);
253 short row_bytes = GetPixRowBytes (pixmap);
4ef0d4d0 254
9ecf6403
YM
255 if (base_addr[y * row_bytes + x / 8] & (1 << (~x & 7)))
256 return PIX_MASK_DRAW;
257 else
258 return PIX_MASK_RETAIN;
259 }
260 else
261 {
262 CGrafPtr old_port;
263 GDHandle old_gdh;
264 RGBColor color;
2a316a84 265
9ecf6403
YM
266 GetGWorld (&old_port, &old_gdh);
267 SetGWorld (ximage, NULL);
268
269 GetCPixel (x, y, &color);
270
271 SetGWorld (old_port, old_gdh);
272 return RGB_TO_ULONG (color.red >> 8, color.green >> 8, color.blue >> 8);
273 }
2ff0845e 274#endif
4ef0d4d0
KS
275}
276
277static void
278XDestroyImage (ximg)
279 XImagePtr ximg;
280{
2ff0845e 281#if !USE_MAC_IMAGE_IO
4ef0d4d0 282 UnlockPixels (GetGWorldPixMap (ximg));
2ff0845e 283#endif
4ef0d4d0 284}
c7fea325
YM
285
286#if USE_CG_DRAWING
2ff0845e
YM
287#if USE_MAC_IMAGE_IO
288void
289mac_data_provider_release_data (info, data, size)
290 void *info;
291 const void *data;
292 size_t size;
293{
294 xfree ((void *)data);
295}
296#endif
297
c7fea325
YM
298static CGImageRef
299mac_create_cg_image_from_image (f, img)
300 struct frame *f;
301 struct image *img;
302{
2ff0845e
YM
303#if USE_MAC_IMAGE_IO
304 XImagePtr ximg = img->pixmap;
305 CGDataProviderRef provider;
306 CGImageRef result;
307
308 if (img->mask)
309 {
310 int x, y;
311 unsigned long color, alpha;
312
313 for (y = 0; y < ximg->height; y++)
314 for (x = 0; x < ximg->width; x++)
315 {
316 color = XGetPixel (ximg, x, y);
317 alpha = XGetPixel (img->mask, x, y);
318 XPutPixel (ximg, x, y,
319 ARGB_TO_ULONG (alpha,
320 RED_FROM_ULONG (color)
321 * alpha / PIX_MASK_DRAW,
322 GREEN_FROM_ULONG (color)
323 * alpha / PIX_MASK_DRAW,
324 BLUE_FROM_ULONG (color)
325 * alpha / PIX_MASK_DRAW));
326 }
327 xfree (img->mask->data);
328 img->mask->data = NULL;
329 }
330 BLOCK_INPUT;
331 provider = CGDataProviderCreateWithData (NULL, ximg->data,
332 ximg->bytes_per_line * ximg->height,
333 mac_data_provider_release_data);
334 ximg->data = NULL;
335 result = CGImageCreate (ximg->width, ximg->height, 8, 32,
336 ximg->bytes_per_line, mac_cg_color_space_rgb,
1802dc0c
YM
337 ((img->mask ? kCGImageAlphaPremultipliedFirst
338 : kCGImageAlphaNoneSkipFirst)
339 | kCGBitmapByteOrder32Host),
340 provider, NULL, 0, kCGRenderingIntentDefault);
2ff0845e
YM
341 CGDataProviderRelease (provider);
342 UNBLOCK_INPUT;
343
344 return result;
345#else
c7fea325
YM
346 Pixmap mask;
347 CGImageRef result = NULL;
348
349 BLOCK_INPUT;
350 if (img->mask)
351 mask = img->mask;
352 else
353 {
354 mask = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
355 img->width, img->height, 1);
356 if (mask)
357 {
358 CGrafPtr old_port;
359 GDHandle old_gdh;
360 Rect r;
361
362 GetGWorld (&old_port, &old_gdh);
363 SetGWorld (mask, NULL);
364 BackColor (blackColor); /* Don't mask. */
365 SetRect (&r, 0, 0, img->width, img->height);
366 EraseRect (&r);
367 SetGWorld (old_port, old_gdh);
368 }
369 }
370 if (mask)
371 {
372 CreateCGImageFromPixMaps (GetGWorldPixMap (img->pixmap),
373 GetGWorldPixMap (mask), &result);
374 if (mask != img->mask)
375 XFreePixmap (FRAME_X_DISPLAY (f), mask);
376 }
377 UNBLOCK_INPUT;
378
379 return result;
2ff0845e 380#endif
c7fea325
YM
381}
382#endif /* USE_CG_DRAWING */
b0da69a7 383#endif /* MAC_OS */
4ef0d4d0 384
edfda783
AR
385#ifdef HAVE_NS
386XImagePtr
387XGetImage (Display *display, Pixmap pixmap, int x, int y,
388 unsigned int width, unsigned int height,
389 unsigned long plane_mask, int format)
390{
6fb5f7da 391 /* TODO: not sure what this function is supposed to do.. */
edfda783
AR
392 ns_retain_object(pixmap);
393 return pixmap;
394}
395
396/* use with imgs created by ns_image_for_XPM */
397unsigned long
398XGetPixel (XImagePtr ximage, int x, int y)
399{
400 return ns_get_pixel(ximage, x, y);
401}
402
403/* use with imgs created by ns_image_for_XPM; alpha set to 1;
404 pixel is assumed to be in form RGB */
405void
406XPutPixel (XImagePtr ximage, int x, int y, unsigned long pixel)
407{
408 ns_put_pixel(ximage, x, y, pixel);
409}
410#endif /* HAVE_NS */
411
4ef0d4d0
KS
412
413/* Functions to access the contents of a bitmap, given an id. */
414
415int
416x_bitmap_height (f, id)
417 FRAME_PTR f;
418 int id;
419{
420 return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].height;
421}
422
423int
424x_bitmap_width (f, id)
425 FRAME_PTR f;
426 int id;
427{
428 return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].width;
429}
430
431#if defined (HAVE_X_WINDOWS) || defined (HAVE_NTGUI)
432int
433x_bitmap_pixmap (f, id)
434 FRAME_PTR f;
435 int id;
436{
437 return (int) FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
438}
439#endif
440
441#ifdef HAVE_X_WINDOWS
442int
443x_bitmap_mask (f, id)
444 FRAME_PTR f;
445 int id;
446{
447 return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].mask;
448}
449#endif
450
451/* Allocate a new bitmap record. Returns index of new record. */
452
453static int
454x_allocate_bitmap_record (f)
455 FRAME_PTR f;
456{
457 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
458 int i;
459
460 if (dpyinfo->bitmaps == NULL)
461 {
462 dpyinfo->bitmaps_size = 10;
463 dpyinfo->bitmaps
464 = (Bitmap_Record *) xmalloc (dpyinfo->bitmaps_size * sizeof (Bitmap_Record));
465 dpyinfo->bitmaps_last = 1;
466 return 1;
467 }
468
469 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
470 return ++dpyinfo->bitmaps_last;
471
472 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
473 if (dpyinfo->bitmaps[i].refcount == 0)
474 return i + 1;
475
476 dpyinfo->bitmaps_size *= 2;
477 dpyinfo->bitmaps
478 = (Bitmap_Record *) xrealloc (dpyinfo->bitmaps,
479 dpyinfo->bitmaps_size * sizeof (Bitmap_Record));
480 return ++dpyinfo->bitmaps_last;
481}
482
483/* Add one reference to the reference count of the bitmap with id ID. */
484
485void
486x_reference_bitmap (f, id)
487 FRAME_PTR f;
488 int id;
489{
490 ++FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
491}
492
493/* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */
494
495int
496x_create_bitmap_from_data (f, bits, width, height)
497 struct frame *f;
498 char *bits;
499 unsigned int width, height;
500{
501 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
502 int id;
503
504#ifdef HAVE_X_WINDOWS
505 Pixmap bitmap;
506 bitmap = XCreateBitmapFromData (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
507 bits, width, height);
508 if (! bitmap)
509 return -1;
510#endif /* HAVE_X_WINDOWS */
511
512#ifdef HAVE_NTGUI
513 Pixmap bitmap;
514 bitmap = CreateBitmap (width, height,
515 FRAME_X_DISPLAY_INFO (XFRAME (frame))->n_planes,
516 FRAME_X_DISPLAY_INFO (XFRAME (frame))->n_cbits,
517 bits);
518 if (! bitmap)
519 return -1;
520#endif /* HAVE_NTGUI */
521
edfda783
AR
522#ifdef HAVE_NS
523 void *bitmap = ns_image_from_XBM(bits, width, height);
524 if (!bitmap)
525 return -1;
526#endif
527
4ef0d4d0 528 id = x_allocate_bitmap_record (f);
4ef0d4d0 529
edfda783
AR
530#ifdef HAVE_NS
531 dpyinfo->bitmaps[id - 1].img = bitmap;
532 dpyinfo->bitmaps[id - 1].depth = 1;
533#endif
534
4ef0d4d0
KS
535 dpyinfo->bitmaps[id - 1].file = NULL;
536 dpyinfo->bitmaps[id - 1].height = height;
537 dpyinfo->bitmaps[id - 1].width = width;
538 dpyinfo->bitmaps[id - 1].refcount = 1;
539
540#ifdef HAVE_X_WINDOWS
541 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
542 dpyinfo->bitmaps[id - 1].have_mask = 0;
543 dpyinfo->bitmaps[id - 1].depth = 1;
544#endif /* HAVE_X_WINDOWS */
545
546#ifdef HAVE_NTGUI
547 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
548 dpyinfo->bitmaps[id - 1].hinst = NULL;
549 dpyinfo->bitmaps[id - 1].depth = 1;
550#endif /* HAVE_NTGUI */
551
552 return id;
553}
554
555/* Create bitmap from file FILE for frame F. */
556
557int
558x_create_bitmap_from_file (f, file)
559 struct frame *f;
560 Lisp_Object file;
561{
edfda783
AR
562 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
563
4ef0d4d0
KS
564#ifdef HAVE_NTGUI
565 return -1; /* W32_TODO : bitmap support */
566#endif /* HAVE_NTGUI */
567
edfda783
AR
568#ifdef HAVE_NS
569 int id;
570 void *bitmap = ns_image_from_file(file);
571
572 if (!bitmap)
573 return -1;
574
575
576 id = x_allocate_bitmap_record (f);
577 dpyinfo->bitmaps[id - 1].img = bitmap;
578 dpyinfo->bitmaps[id - 1].refcount = 1;
579 dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (SBYTES (file) + 1);
580 dpyinfo->bitmaps[id - 1].depth = 1;
581 dpyinfo->bitmaps[id - 1].height = ns_image_width(bitmap);
582 dpyinfo->bitmaps[id - 1].width = ns_image_height(bitmap);
583 strcpy (dpyinfo->bitmaps[id - 1].file, SDATA (file));
584 return id;
585#endif
586
4ef0d4d0 587#ifdef HAVE_X_WINDOWS
4ef0d4d0
KS
588 unsigned int width, height;
589 Pixmap bitmap;
590 int xhot, yhot, result, id;
591 Lisp_Object found;
592 int fd;
593 char *filename;
594
595 /* Look for an existing bitmap with the same name. */
596 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
597 {
598 if (dpyinfo->bitmaps[id].refcount
599 && dpyinfo->bitmaps[id].file
600 && !strcmp (dpyinfo->bitmaps[id].file, (char *) SDATA (file)))
601 {
602 ++dpyinfo->bitmaps[id].refcount;
603 return id + 1;
604 }
605 }
606
607 /* Search bitmap-file-path for the file, if appropriate. */
608 fd = openp (Vx_bitmap_file_path, file, Qnil, &found, Qnil);
609 if (fd < 0)
610 return -1;
611 emacs_close (fd);
612
613 filename = (char *) SDATA (found);
614
615 result = XReadBitmapFile (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
616 filename, &width, &height, &bitmap, &xhot, &yhot);
617 if (result != BitmapSuccess)
618 return -1;
619
620 id = x_allocate_bitmap_record (f);
621 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
622 dpyinfo->bitmaps[id - 1].have_mask = 0;
623 dpyinfo->bitmaps[id - 1].refcount = 1;
624 dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (SBYTES (file) + 1);
625 dpyinfo->bitmaps[id - 1].depth = 1;
626 dpyinfo->bitmaps[id - 1].height = height;
627 dpyinfo->bitmaps[id - 1].width = width;
628 strcpy (dpyinfo->bitmaps[id - 1].file, SDATA (file));
629
630 return id;
631#endif /* HAVE_X_WINDOWS */
632}
633
634/* Free bitmap B. */
635
636static void
65342ae3 637free_bitmap_record (dpyinfo, bm)
4ef0d4d0
KS
638 Display_Info *dpyinfo;
639 Bitmap_Record *bm;
640{
641#ifdef HAVE_X_WINDOWS
642 XFreePixmap (dpyinfo->display, bm->pixmap);
643 if (bm->have_mask)
644 XFreePixmap (dpyinfo->display, bm->mask);
645#endif /* HAVE_X_WINDOWS */
646
647#ifdef HAVE_NTGUI
648 DeleteObject (bm->pixmap);
649#endif /* HAVE_NTGUI */
650
edfda783
AR
651#ifdef HAVE_NS
652 ns_release_object(bm->img);
653#endif
654
4ef0d4d0
KS
655 if (bm->file)
656 {
657 xfree (bm->file);
658 bm->file = NULL;
659 }
660}
661
662/* Remove reference to bitmap with id number ID. */
663
664void
665x_destroy_bitmap (f, id)
666 FRAME_PTR f;
667 int id;
668{
669 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
670
671 if (id > 0)
672 {
673 Bitmap_Record *bm = &dpyinfo->bitmaps[id - 1];
674
675 if (--bm->refcount == 0)
676 {
677 BLOCK_INPUT;
65342ae3 678 free_bitmap_record (dpyinfo, bm);
4ef0d4d0
KS
679 UNBLOCK_INPUT;
680 }
681 }
682}
683
684/* Free all the bitmaps for the display specified by DPYINFO. */
685
686void
687x_destroy_all_bitmaps (dpyinfo)
688 Display_Info *dpyinfo;
689{
690 int i;
691 Bitmap_Record *bm = dpyinfo->bitmaps;
692
693 for (i = 0; i < dpyinfo->bitmaps_last; i++, bm++)
694 if (bm->refcount > 0)
65342ae3 695 free_bitmap_record (dpyinfo, bm);
4ef0d4d0
KS
696
697 dpyinfo->bitmaps_last = 0;
698}
699
700
701#ifdef HAVE_X_WINDOWS
702
703/* Useful functions defined in the section
704 `Image type independent image structures' below. */
705
6ac3c7bb
KS
706static unsigned long four_corners_best P_ ((XImagePtr ximg,
707 int *corners,
708 unsigned long width,
4ef0d4d0
KS
709 unsigned long height));
710
711static int x_create_x_image_and_pixmap P_ ((struct frame *f, int width, int height,
712 int depth, XImagePtr *ximg,
713 Pixmap *pixmap));
714
715static void x_destroy_x_image P_ ((XImagePtr ximg));
716
717
718/* Create a mask of a bitmap. Note is this not a perfect mask.
719 It's nicer with some borders in this context */
720
721int
722x_create_bitmap_mask (f, id)
723 struct frame *f;
724 int id;
725{
726 Pixmap pixmap, mask;
727 XImagePtr ximg, mask_img;
728 unsigned long width, height;
729 int result;
730 unsigned long bg;
731 unsigned long x, y, xp, xm, yp, ym;
732 GC gc;
733
734 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
735
736 if (!(id > 0))
737 return -1;
738
739 pixmap = x_bitmap_pixmap (f, id);
740 width = x_bitmap_width (f, id);
741 height = x_bitmap_height (f, id);
742
743 BLOCK_INPUT;
744 ximg = XGetImage (FRAME_X_DISPLAY (f), pixmap, 0, 0, width, height,
745 ~0, ZPixmap);
746
747 if (!ximg)
748 {
749 UNBLOCK_INPUT;
750 return -1;
751 }
752
753 result = x_create_x_image_and_pixmap (f, width, height, 1, &mask_img, &mask);
754
755 UNBLOCK_INPUT;
756 if (!result)
757 {
758 XDestroyImage (ximg);
759 return -1;
760 }
761
6ac3c7bb 762 bg = four_corners_best (ximg, NULL, width, height);
4ef0d4d0
KS
763
764 for (y = 0; y < ximg->height; ++y)
765 {
766 for (x = 0; x < ximg->width; ++x)
767 {
768 xp = x != ximg->width - 1 ? x + 1 : 0;
769 xm = x != 0 ? x - 1 : ximg->width - 1;
770 yp = y != ximg->height - 1 ? y + 1 : 0;
771 ym = y != 0 ? y - 1 : ximg->height - 1;
772 if (XGetPixel (ximg, x, y) == bg
773 && XGetPixel (ximg, x, yp) == bg
774 && XGetPixel (ximg, x, ym) == bg
775 && XGetPixel (ximg, xp, y) == bg
776 && XGetPixel (ximg, xp, yp) == bg
777 && XGetPixel (ximg, xp, ym) == bg
778 && XGetPixel (ximg, xm, y) == bg
779 && XGetPixel (ximg, xm, yp) == bg
780 && XGetPixel (ximg, xm, ym) == bg)
781 XPutPixel (mask_img, x, y, 0);
782 else
783 XPutPixel (mask_img, x, y, 1);
784 }
785 }
786
787 xassert (interrupt_input_blocked);
788 gc = XCreateGC (FRAME_X_DISPLAY (f), mask, 0, NULL);
789 XPutImage (FRAME_X_DISPLAY (f), mask, gc, mask_img, 0, 0, 0, 0,
790 width, height);
791 XFreeGC (FRAME_X_DISPLAY (f), gc);
792
793 dpyinfo->bitmaps[id - 1].have_mask = 1;
794 dpyinfo->bitmaps[id - 1].mask = mask;
795
796 XDestroyImage (ximg);
797 x_destroy_x_image (mask_img);
798
799 return 0;
800}
801
802#endif /* HAVE_X_WINDOWS */
803
804
805/***********************************************************************
806 Image types
807 ***********************************************************************/
808
809/* Value is the number of elements of vector VECTOR. */
810
811#define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
812
813/* List of supported image types. Use define_image_type to add new
814 types. Use lookup_image_type to find a type for a given symbol. */
815
816static struct image_type *image_types;
817
0855eb52
JB
818/* A list of symbols, one for each supported image type. */
819
820Lisp_Object Vimage_types;
821
2a611c1a
JB
822/* An alist of image types and libraries that implement the type. */
823
824Lisp_Object Vimage_library_alist;
825
0855eb52
JB
826/* Cache for delayed-loading image types. */
827
828static Lisp_Object Vimage_type_cache;
829
4ef0d4d0
KS
830/* The symbol `xbm' which is used as the type symbol for XBM images. */
831
832Lisp_Object Qxbm;
833
834/* Keywords. */
835
836extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
e047f448 837extern Lisp_Object QCdata, QCtype;
e1dfec15 838extern Lisp_Object Qcenter;
e047f448 839Lisp_Object QCascent, QCmargin, QCrelief, Qcount;
4ef0d4d0
KS
840Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
841Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
842
843/* Other symbols. */
844
845Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
4ef0d4d0
KS
846
847/* Time in seconds after which images should be removed from the cache
848 if not displayed. */
849
850Lisp_Object Vimage_cache_eviction_delay;
851
852/* Function prototypes. */
853
0855eb52 854static Lisp_Object define_image_type P_ ((struct image_type *type, int loaded));
4ef0d4d0
KS
855static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
856static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
857static void x_laplace P_ ((struct frame *, struct image *));
858static void x_emboss P_ ((struct frame *, struct image *));
859static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
860 Lisp_Object));
861
0855eb52
JB
862#define CACHE_IMAGE_TYPE(type, status) \
863 do { Vimage_type_cache = Fcons (Fcons (type, status), Vimage_type_cache); } while (0)
864
865#define ADD_IMAGE_TYPE(type) \
866 do { Vimage_types = Fcons (type, Vimage_types); } while (0)
4ef0d4d0
KS
867
868/* Define a new image type from TYPE. This adds a copy of TYPE to
0855eb52 869 image_types and caches the loading status of TYPE. */
4ef0d4d0 870
0855eb52
JB
871static Lisp_Object
872define_image_type (type, loaded)
4ef0d4d0 873 struct image_type *type;
0855eb52 874 int loaded;
4ef0d4d0 875{
0855eb52
JB
876 Lisp_Object success;
877
878 if (!loaded)
879 success = Qnil;
880 else
881 {
882 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
883 The initialized data segment is read-only. */
884 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
885 bcopy (type, p, sizeof *p);
886 p->next = image_types;
887 image_types = p;
888 success = Qt;
889 }
890
adac86db 891 CACHE_IMAGE_TYPE (*type->type, success);
0855eb52 892 return success;
4ef0d4d0
KS
893}
894
895
896/* Look up image type SYMBOL, and return a pointer to its image_type
897 structure. Value is null if SYMBOL is not a known image type. */
898
899static INLINE struct image_type *
900lookup_image_type (symbol)
901 Lisp_Object symbol;
902{
903 struct image_type *type;
904
803aac3e 905 /* We must initialize the image-type if it hasn't been already. */
2a611c1a 906 if (NILP (Finit_image_library (symbol, Vimage_library_alist)))
803aac3e
MB
907 return 0; /* unimplemented */
908
4ef0d4d0
KS
909 for (type = image_types; type; type = type->next)
910 if (EQ (symbol, *type->type))
911 break;
912
913 return type;
914}
915
916
917/* Value is non-zero if OBJECT is a valid Lisp image specification. A
918 valid image specification is a list whose car is the symbol
919 `image', and whose rest is a property list. The property list must
920 contain a value for key `:type'. That value must be the name of a
921 supported image type. The rest of the property list depends on the
922 image type. */
923
924int
925valid_image_p (object)
926 Lisp_Object object;
927{
928 int valid_p = 0;
929
930 if (IMAGEP (object))
931 {
932 Lisp_Object tem;
933
934 for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem))
935 if (EQ (XCAR (tem), QCtype))
936 {
937 tem = XCDR (tem);
938 if (CONSP (tem) && SYMBOLP (XCAR (tem)))
939 {
940 struct image_type *type;
941 type = lookup_image_type (XCAR (tem));
942 if (type)
943 valid_p = type->valid_p (object);
944 }
945
946 break;
947 }
948 }
949
950 return valid_p;
951}
952
953
954/* Log error message with format string FORMAT and argument ARG.
955 Signaling an error, e.g. when an image cannot be loaded, is not a
956 good idea because this would interrupt redisplay, and the error
957 message display would lead to another redisplay. This function
958 therefore simply displays a message. */
959
960static void
961image_error (format, arg1, arg2)
962 char *format;
963 Lisp_Object arg1, arg2;
964{
965 add_to_log (format, arg1, arg2);
966}
967
968
969\f
970/***********************************************************************
971 Image specifications
972 ***********************************************************************/
973
974enum image_value_type
975{
976 IMAGE_DONT_CHECK_VALUE_TYPE,
977 IMAGE_STRING_VALUE,
978 IMAGE_STRING_OR_NIL_VALUE,
979 IMAGE_SYMBOL_VALUE,
980 IMAGE_POSITIVE_INTEGER_VALUE,
981 IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
982 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
983 IMAGE_ASCENT_VALUE,
984 IMAGE_INTEGER_VALUE,
985 IMAGE_FUNCTION_VALUE,
986 IMAGE_NUMBER_VALUE,
987 IMAGE_BOOL_VALUE
988};
989
990/* Structure used when parsing image specifications. */
991
992struct image_keyword
993{
994 /* Name of keyword. */
995 char *name;
996
997 /* The type of value allowed. */
998 enum image_value_type type;
999
1000 /* Non-zero means key must be present. */
1001 int mandatory_p;
1002
1003 /* Used to recognize duplicate keywords in a property list. */
1004 int count;
1005
1006 /* The value that was found. */
1007 Lisp_Object value;
1008};
1009
1010
1011static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
1012 int, Lisp_Object));
1013static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
1014
1015
1016/* Parse image spec SPEC according to KEYWORDS. A valid image spec
1017 has the format (image KEYWORD VALUE ...). One of the keyword/
1018 value pairs must be `:type TYPE'. KEYWORDS is a vector of
1019 image_keywords structures of size NKEYWORDS describing other
1020 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
1021
1022static int
1023parse_image_spec (spec, keywords, nkeywords, type)
1024 Lisp_Object spec;
1025 struct image_keyword *keywords;
1026 int nkeywords;
1027 Lisp_Object type;
1028{
1029 int i;
1030 Lisp_Object plist;
1031
1032 if (!IMAGEP (spec))
1033 return 0;
1034
1035 plist = XCDR (spec);
1036 while (CONSP (plist))
1037 {
1038 Lisp_Object key, value;
1039
1040 /* First element of a pair must be a symbol. */
1041 key = XCAR (plist);
1042 plist = XCDR (plist);
1043 if (!SYMBOLP (key))
1044 return 0;
1045
1046 /* There must follow a value. */
1047 if (!CONSP (plist))
1048 return 0;
1049 value = XCAR (plist);
1050 plist = XCDR (plist);
1051
1052 /* Find key in KEYWORDS. Error if not found. */
1053 for (i = 0; i < nkeywords; ++i)
1054 if (strcmp (keywords[i].name, SDATA (SYMBOL_NAME (key))) == 0)
1055 break;
1056
1057 if (i == nkeywords)
1058 continue;
1059
1060 /* Record that we recognized the keyword. If a keywords
1061 was found more than once, it's an error. */
1062 keywords[i].value = value;
1063 ++keywords[i].count;
1064
1065 if (keywords[i].count > 1)
1066 return 0;
1067
1068 /* Check type of value against allowed type. */
1069 switch (keywords[i].type)
1070 {
1071 case IMAGE_STRING_VALUE:
1072 if (!STRINGP (value))
1073 return 0;
1074 break;
1075
1076 case IMAGE_STRING_OR_NIL_VALUE:
1077 if (!STRINGP (value) && !NILP (value))
1078 return 0;
1079 break;
1080
1081 case IMAGE_SYMBOL_VALUE:
1082 if (!SYMBOLP (value))
1083 return 0;
1084 break;
1085
1086 case IMAGE_POSITIVE_INTEGER_VALUE:
1087 if (!INTEGERP (value) || XINT (value) <= 0)
1088 return 0;
1089 break;
1090
1091 case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
1092 if (INTEGERP (value) && XINT (value) >= 0)
1093 break;
1094 if (CONSP (value)
1095 && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
1096 && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
1097 break;
1098 return 0;
1099
1100 case IMAGE_ASCENT_VALUE:
1101 if (SYMBOLP (value) && EQ (value, Qcenter))
1102 break;
1103 else if (INTEGERP (value)
1104 && XINT (value) >= 0
1105 && XINT (value) <= 100)
1106 break;
1107 return 0;
1108
1109 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
1110 if (!INTEGERP (value) || XINT (value) < 0)
1111 return 0;
1112 break;
1113
1114 case IMAGE_DONT_CHECK_VALUE_TYPE:
1115 break;
1116
1117 case IMAGE_FUNCTION_VALUE:
1118 value = indirect_function (value);
1119 if (SUBRP (value)
1120 || COMPILEDP (value)
1121 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
1122 break;
1123 return 0;
1124
1125 case IMAGE_NUMBER_VALUE:
1126 if (!INTEGERP (value) && !FLOATP (value))
1127 return 0;
1128 break;
1129
1130 case IMAGE_INTEGER_VALUE:
1131 if (!INTEGERP (value))
1132 return 0;
1133 break;
1134
1135 case IMAGE_BOOL_VALUE:
1136 if (!NILP (value) && !EQ (value, Qt))
1137 return 0;
1138 break;
1139
1140 default:
1141 abort ();
1142 break;
1143 }
1144
1145 if (EQ (key, QCtype) && !EQ (type, value))
1146 return 0;
1147 }
1148
1149 /* Check that all mandatory fields are present. */
1150 for (i = 0; i < nkeywords; ++i)
1151 if (keywords[i].mandatory_p && keywords[i].count == 0)
1152 return 0;
1153
1154 return NILP (plist);
1155}
1156
1157
1158/* Return the value of KEY in image specification SPEC. Value is nil
1159 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
1160 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
1161
1162static Lisp_Object
1163image_spec_value (spec, key, found)
1164 Lisp_Object spec, key;
1165 int *found;
1166{
1167 Lisp_Object tail;
1168
1169 xassert (valid_image_p (spec));
1170
1171 for (tail = XCDR (spec);
1172 CONSP (tail) && CONSP (XCDR (tail));
1173 tail = XCDR (XCDR (tail)))
1174 {
1175 if (EQ (XCAR (tail), key))
1176 {
1177 if (found)
1178 *found = 1;
1179 return XCAR (XCDR (tail));
1180 }
1181 }
1182
1183 if (found)
1184 *found = 0;
1185 return Qnil;
1186}
1187
1188
1189DEFUN ("image-size", Fimage_size, Simage_size, 1, 3, 0,
1190 doc: /* Return the size of image SPEC as pair (WIDTH . HEIGHT).
1191PIXELS non-nil means return the size in pixels, otherwise return the
1192size in canonical character units.
1193FRAME is the frame on which the image will be displayed. FRAME nil
1194or omitted means use the selected frame. */)
1195 (spec, pixels, frame)
1196 Lisp_Object spec, pixels, frame;
1197{
1198 Lisp_Object size;
1199
1200 size = Qnil;
1201 if (valid_image_p (spec))
1202 {
1203 struct frame *f = check_x_frame (frame);
1204 int id = lookup_image (f, spec);
1205 struct image *img = IMAGE_FROM_ID (f, id);
1206 int width = img->width + 2 * img->hmargin;
1207 int height = img->height + 2 * img->vmargin;
1208
1209 if (NILP (pixels))
1210 size = Fcons (make_float ((double) width / FRAME_COLUMN_WIDTH (f)),
1211 make_float ((double) height / FRAME_LINE_HEIGHT (f)));
1212 else
1213 size = Fcons (make_number (width), make_number (height));
1214 }
1215 else
1216 error ("Invalid image specification");
1217
1218 return size;
1219}
1220
1221
1222DEFUN ("image-mask-p", Fimage_mask_p, Simage_mask_p, 1, 2, 0,
1223 doc: /* Return t if image SPEC has a mask bitmap.
1224FRAME is the frame on which the image will be displayed. FRAME nil
1225or omitted means use the selected frame. */)
1226 (spec, frame)
1227 Lisp_Object spec, frame;
1228{
1229 Lisp_Object mask;
1230
1231 mask = Qnil;
1232 if (valid_image_p (spec))
1233 {
1234 struct frame *f = check_x_frame (frame);
1235 int id = lookup_image (f, spec);
1236 struct image *img = IMAGE_FROM_ID (f, id);
1237 if (img->mask)
1238 mask = Qt;
1239 }
1240 else
1241 error ("Invalid image specification");
1242
1243 return mask;
1244}
1245
6ac3c7bb
KS
1246DEFUN ("image-extension-data", Fimage_extension_data, Simage_extension_data, 1, 2, 0,
1247 doc: /* Return extension data for image SPEC.
1248FRAME is the frame on which the image will be displayed. FRAME nil
1249or omitted means use the selected frame. */)
1250 (spec, frame)
1251 Lisp_Object spec, frame;
1252{
1253 Lisp_Object ext;
1254
1255 ext = Qnil;
1256 if (valid_image_p (spec))
1257 {
1258 struct frame *f = check_x_frame (frame);
1259 int id = lookup_image (f, spec);
1260 struct image *img = IMAGE_FROM_ID (f, id);
1261 ext = img->data.lisp_val;
1262 }
1263
1264 return ext;
1265}
1266
4ef0d4d0
KS
1267\f
1268/***********************************************************************
1269 Image type independent image structures
1270 ***********************************************************************/
1271
1272static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
1273static void free_image P_ ((struct frame *f, struct image *img));
f1f25b99 1274static int check_image_size P_ ((struct frame *f, int width, int height));
4ef0d4d0 1275
f1f25b99
CY
1276#define MAX_IMAGE_SIZE 6.0
1277Lisp_Object Vmax_image_size;
4ef0d4d0
KS
1278
1279/* Allocate and return a new image structure for image specification
1280 SPEC. SPEC has a hash value of HASH. */
1281
1282static struct image *
1283make_image (spec, hash)
1284 Lisp_Object spec;
1285 unsigned hash;
1286{
1287 struct image *img = (struct image *) xmalloc (sizeof *img);
a2bc5bdd 1288 Lisp_Object file = image_spec_value (spec, QCfile, NULL);
4ef0d4d0
KS
1289
1290 xassert (valid_image_p (spec));
1291 bzero (img, sizeof *img);
a2bc5bdd 1292 img->dependencies = NILP (file) ? Qnil : list1 (file);
4ef0d4d0
KS
1293 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
1294 xassert (img->type != NULL);
1295 img->spec = spec;
1296 img->data.lisp_val = Qnil;
1297 img->ascent = DEFAULT_IMAGE_ASCENT;
1298 img->hash = hash;
6ac3c7bb 1299 img->corners[BOT_CORNER] = -1; /* Full image */
4ef0d4d0
KS
1300 return img;
1301}
1302
1303
1304/* Free image IMG which was used on frame F, including its resources. */
1305
1306static void
1307free_image (f, img)
1308 struct frame *f;
1309 struct image *img;
1310{
1311 if (img)
1312 {
354884c4 1313 struct image_cache *c = FRAME_IMAGE_CACHE (f);
4ef0d4d0
KS
1314
1315 /* Remove IMG from the hash table of its cache. */
1316 if (img->prev)
1317 img->prev->next = img->next;
1318 else
1319 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
1320
1321 if (img->next)
1322 img->next->prev = img->prev;
1323
1324 c->images[img->id] = NULL;
1325
1326 /* Free resources, then free IMG. */
1327 img->type->free (f, img);
1328 xfree (img);
1329 }
1330}
1331
f1f25b99
CY
1332/* Return 1 if the given widths and heights are valid for display;
1333 otherwise, return 0. */
1334
1335int
1336check_image_size (f, width, height)
1337 struct frame *f;
1338 int width;
1339 int height;
1340{
7df4765a 1341 int w, h;
f1f25b99 1342
7df4765a 1343 if (width <= 0 || height <= 0)
f1f25b99
CY
1344 return 0;
1345
7df4765a
KS
1346 if (INTEGERP (Vmax_image_size))
1347 w = h = XINT (Vmax_image_size);
1348 else if (FLOATP (Vmax_image_size))
1349 {
1350 if (f != NULL)
1351 {
1352 w = FRAME_PIXEL_WIDTH (f);
1353 h = FRAME_PIXEL_HEIGHT (f);
1354 }
1355 else
1356 w = h = 1024; /* Arbitrary size for unknown frame. */
1357 w = (int) (XFLOAT_DATA (Vmax_image_size) * w);
1358 h = (int) (XFLOAT_DATA (Vmax_image_size) * h);
1359 }
1360 else
1361 return 1;
1362
1363 return (width <= w && height <= h);
f1f25b99 1364}
4ef0d4d0
KS
1365
1366/* Prepare image IMG for display on frame F. Must be called before
1367 drawing an image. */
1368
1369void
1370prepare_image_for_display (f, img)
1371 struct frame *f;
1372 struct image *img;
1373{
1374 EMACS_TIME t;
1375
1376 /* We're about to display IMG, so set its timestamp to `now'. */
1377 EMACS_GET_TIME (t);
1378 img->timestamp = EMACS_SECS (t);
1379
1380 /* If IMG doesn't have a pixmap yet, load it now, using the image
1381 type dependent loader function. */
1382 if (img->pixmap == NO_PIXMAP && !img->load_failed_p)
1383 img->load_failed_p = img->type->load (f, img) == 0;
c7fea325 1384
4ef0d4d0
KS
1385}
1386
1387
1388/* Value is the number of pixels for the ascent of image IMG when
1389 drawn in face FACE. */
1390
1391int
1938bc36 1392image_ascent (img, face, slice)
4ef0d4d0
KS
1393 struct image *img;
1394 struct face *face;
1938bc36 1395 struct glyph_slice *slice;
4ef0d4d0 1396{
1938bc36 1397 int height;
4ef0d4d0
KS
1398 int ascent;
1399
1938bc36
KS
1400 if (slice->height == img->height)
1401 height = img->height + img->vmargin;
1402 else if (slice->y == 0)
1403 height = slice->height + img->vmargin;
1404 else
1405 height = slice->height;
1406
4ef0d4d0
KS
1407 if (img->ascent == CENTERED_IMAGE_ASCENT)
1408 {
1409 if (face->font)
1410 {
1411#ifdef HAVE_NTGUI
1412 /* W32 specific version. Why?. ++kfs */
5fc9fdeb
JR
1413 ascent = height / 2 - (FONT_DESCENT (face->font)
1414 - FONT_BASE (face->font)) / 2;
4ef0d4d0
KS
1415#else
1416 /* This expression is arranged so that if the image can't be
1417 exactly centered, it will be moved slightly up. This is
1418 because a typical font is `top-heavy' (due to the presence
1419 uppercase letters), so the image placement should err towards
1420 being top-heavy too. It also just generally looks better. */
edfda783
AR
1421 ascent = (height + FONT_BASE(face->font)
1422 - FONT_DESCENT(face->font) + 1) / 2;
4ef0d4d0
KS
1423#endif /* HAVE_NTGUI */
1424 }
1425 else
1426 ascent = height / 2;
1427 }
1428 else
1429 ascent = (int) (height * img->ascent / 100.0);
1430
1431 return ascent;
1432}
1433
1434\f
1435/* Image background colors. */
1436
1437/* Find the "best" corner color of a bitmap.
1438 On W32, XIMG is assumed to a device context with the bitmap selected. */
1439
1440static RGB_PIXEL_COLOR
6ac3c7bb 1441four_corners_best (ximg, corners, width, height)
4ef0d4d0 1442 XImagePtr_or_DC ximg;
6ac3c7bb 1443 int *corners;
4ef0d4d0
KS
1444 unsigned long width, height;
1445{
6ac3c7bb 1446 RGB_PIXEL_COLOR corner_pixels[4], best;
4ef0d4d0
KS
1447 int i, best_count;
1448
6ac3c7bb
KS
1449 if (corners && corners[BOT_CORNER] >= 0)
1450 {
1451 /* Get the colors at the corner_pixels of ximg. */
1452 corner_pixels[0] = GET_PIXEL (ximg, corners[LEFT_CORNER], corners[TOP_CORNER]);
1453 corner_pixels[1] = GET_PIXEL (ximg, corners[RIGHT_CORNER] - 1, corners[TOP_CORNER]);
1454 corner_pixels[2] = GET_PIXEL (ximg, corners[RIGHT_CORNER] - 1, corners[BOT_CORNER] - 1);
1455 corner_pixels[3] = GET_PIXEL (ximg, corners[LEFT_CORNER], corners[BOT_CORNER] - 1);
1456 }
1457 else
1458 {
1459 /* Get the colors at the corner_pixels of ximg. */
1460 corner_pixels[0] = GET_PIXEL (ximg, 0, 0);
1461 corner_pixels[1] = GET_PIXEL (ximg, width - 1, 0);
1462 corner_pixels[2] = GET_PIXEL (ximg, width - 1, height - 1);
1463 corner_pixels[3] = GET_PIXEL (ximg, 0, height - 1);
1464 }
4ef0d4d0
KS
1465 /* Choose the most frequently found color as background. */
1466 for (i = best_count = 0; i < 4; ++i)
1467 {
1468 int j, n;
1469
1470 for (j = n = 0; j < 4; ++j)
6ac3c7bb 1471 if (corner_pixels[i] == corner_pixels[j])
4ef0d4d0
KS
1472 ++n;
1473
1474 if (n > best_count)
6ac3c7bb 1475 best = corner_pixels[i], best_count = n;
4ef0d4d0
KS
1476 }
1477
1478 return best;
1479}
1480
1481/* Portability macros */
1482
1483#ifdef HAVE_NTGUI
1484
1485#define Destroy_Image(img_dc, prev) \
1486 do { SelectObject (img_dc, prev); DeleteDC (img_dc); } while (0)
1487
1488#define Free_Pixmap(display, pixmap) \
1489 DeleteObject (pixmap)
1490
edfda783
AR
1491#elif defined (HAVE_NS)
1492
1493#define Destroy_Image(ximg, dummy) \
1494 ns_release_object(ximg)
1495
1496#define Free_Pixmap(display, pixmap) \
1497 ns_release_object(pixmap)
1498
4ef0d4d0
KS
1499#else
1500
1501#define Destroy_Image(ximg, dummy) \
1502 XDestroyImage (ximg)
1503
1504#define Free_Pixmap(display, pixmap) \
1505 XFreePixmap (display, pixmap)
1506
edfda783 1507#endif /* !HAVE_NTGUI && !HAVE_NS */
4ef0d4d0
KS
1508
1509
1510/* Return the `background' field of IMG. If IMG doesn't have one yet,
1511 it is guessed heuristically. If non-zero, XIMG is an existing
1512 XImage object (or device context with the image selected on W32) to
1f026899 1513 use for the heuristic. */
4ef0d4d0
KS
1514
1515RGB_PIXEL_COLOR
1516image_background (img, f, ximg)
1517 struct image *img;
1518 struct frame *f;
1519 XImagePtr_or_DC ximg;
1520{
1521 if (! img->background_valid)
1522 /* IMG doesn't have a background yet, try to guess a reasonable value. */
1523 {
1524 int free_ximg = !ximg;
1525#ifdef HAVE_NTGUI
1526 HGDIOBJ prev;
1527#endif /* HAVE_NTGUI */
1528
1529 if (free_ximg)
1530 {
1531#ifndef HAVE_NTGUI
1532 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
1533 0, 0, img->width, img->height, ~0, ZPixmap);
1534#else
1535 HDC frame_dc = get_frame_dc (f);
1536 ximg = CreateCompatibleDC (frame_dc);
1537 release_frame_dc (f, frame_dc);
1538 prev = SelectObject (ximg, img->pixmap);
1539#endif /* !HAVE_NTGUI */
1540 }
1541
6ac3c7bb 1542 img->background = four_corners_best (ximg, img->corners, img->width, img->height);
4ef0d4d0
KS
1543
1544 if (free_ximg)
1545 Destroy_Image (ximg, prev);
1f026899 1546
4ef0d4d0
KS
1547 img->background_valid = 1;
1548 }
1549
1550 return img->background;
1551}
1552
1553/* Return the `background_transparent' field of IMG. If IMG doesn't
1554 have one yet, it is guessed heuristically. If non-zero, MASK is an
1555 existing XImage object to use for the heuristic. */
1556
1557int
1558image_background_transparent (img, f, mask)
1559 struct image *img;
1560 struct frame *f;
1561 XImagePtr_or_DC mask;
1562{
1563 if (! img->background_transparent_valid)
1564 /* IMG doesn't have a background yet, try to guess a reasonable value. */
1565 {
1566 if (img->mask)
1567 {
1568 int free_mask = !mask;
1569#ifdef HAVE_NTGUI
1570 HGDIOBJ prev;
1571#endif /* HAVE_NTGUI */
1572
1573 if (free_mask)
1574 {
1575#ifndef HAVE_NTGUI
1576 mask = XGetImage (FRAME_X_DISPLAY (f), img->mask,
1577 0, 0, img->width, img->height, ~0, ZPixmap);
1578#else
1579 HDC frame_dc = get_frame_dc (f);
1580 mask = CreateCompatibleDC (frame_dc);
1581 release_frame_dc (f, frame_dc);
1582 prev = SelectObject (mask, img->mask);
1583#endif /* HAVE_NTGUI */
1584 }
1585
1586 img->background_transparent
6ac3c7bb 1587 = (four_corners_best (mask, img->corners, img->width, img->height) == PIX_MASK_RETAIN);
4ef0d4d0
KS
1588
1589 if (free_mask)
1590 Destroy_Image (mask, prev);
1591 }
1592 else
1593 img->background_transparent = 0;
1594
1595 img->background_transparent_valid = 1;
1596 }
1597
1598 return img->background_transparent;
1599}
1600
1601\f
1602/***********************************************************************
1603 Helper functions for X image types
1604 ***********************************************************************/
1605
1606static void x_clear_image_1 P_ ((struct frame *, struct image *, int,
1607 int, int));
1608static void x_clear_image P_ ((struct frame *f, struct image *img));
1609static unsigned long x_alloc_image_color P_ ((struct frame *f,
1610 struct image *img,
1611 Lisp_Object color_name,
1612 unsigned long dflt));
1613
1614
1615/* Clear X resources of image IMG on frame F. PIXMAP_P non-zero means
1616 free the pixmap if any. MASK_P non-zero means clear the mask
1617 pixmap if any. COLORS_P non-zero means free colors allocated for
1618 the image, if any. */
1619
1620static void
1621x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p)
1622 struct frame *f;
1623 struct image *img;
1624 int pixmap_p, mask_p, colors_p;
1625{
1626 if (pixmap_p && img->pixmap)
1627 {
1628 Free_Pixmap (FRAME_X_DISPLAY (f), img->pixmap);
1629 img->pixmap = NO_PIXMAP;
5a06864f 1630 /* NOTE (HAVE_NS): background color is NOT an indexed color! */
4ef0d4d0
KS
1631 img->background_valid = 0;
1632 }
1633
1634 if (mask_p && img->mask)
1635 {
1636 Free_Pixmap (FRAME_X_DISPLAY (f), img->mask);
1637 img->mask = NO_PIXMAP;
1638 img->background_transparent_valid = 0;
1639 }
1640
1641 if (colors_p && img->ncolors)
1642 {
4ef0d4d0
KS
1643 /* W32_TODO: color table support. */
1644#ifdef HAVE_X_WINDOWS
1645 x_free_colors (f, img->colors, img->ncolors);
1646#endif /* HAVE_X_WINDOWS */
1647 xfree (img->colors);
1648 img->colors = NULL;
1649 img->ncolors = 0;
1650 }
c7fea325 1651
4ef0d4d0
KS
1652}
1653
1654/* Free X resources of image IMG which is used on frame F. */
1655
1656static void
1657x_clear_image (f, img)
1658 struct frame *f;
1659 struct image *img;
1660{
1661 BLOCK_INPUT;
1662 x_clear_image_1 (f, img, 1, 1, 1);
1663 UNBLOCK_INPUT;
1664}
1665
1666
1667/* Allocate color COLOR_NAME for image IMG on frame F. If color
1668 cannot be allocated, use DFLT. Add a newly allocated color to
1669 IMG->colors, so that it can be freed again. Value is the pixel
1670 color. */
1671
1672static unsigned long
1673x_alloc_image_color (f, img, color_name, dflt)
1674 struct frame *f;
1675 struct image *img;
1676 Lisp_Object color_name;
1677 unsigned long dflt;
1678{
1679 XColor color;
1680 unsigned long result;
1681
1682 xassert (STRINGP (color_name));
1683
1684 if (x_defined_color (f, SDATA (color_name), &color, 1))
1685 {
1686 /* This isn't called frequently so we get away with simply
1687 reallocating the color vector to the needed size, here. */
1688 ++img->ncolors;
1689 img->colors =
1690 (unsigned long *) xrealloc (img->colors,
1691 img->ncolors * sizeof *img->colors);
1692 img->colors[img->ncolors - 1] = color.pixel;
1693 result = color.pixel;
1694 }
1695 else
1696 result = dflt;
1697
1698 return result;
1699}
1700
1701
1702\f
1703/***********************************************************************
1704 Image Cache
1705 ***********************************************************************/
1706
d3c35d17 1707static struct image *search_image_cache P_ ((struct frame *, Lisp_Object, unsigned));
4ef0d4d0
KS
1708static void cache_image P_ ((struct frame *f, struct image *img));
1709static void postprocess_image P_ ((struct frame *, struct image *));
1710
1711/* Return a new, initialized image cache that is allocated from the
1712 heap. Call free_image_cache to free an image cache. */
1713
1714struct image_cache *
1715make_image_cache ()
1716{
1717 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
1718 int size;
1719
1720 bzero (c, sizeof *c);
1721 c->size = 50;
1722 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
1723 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
1724 c->buckets = (struct image **) xmalloc (size);
1725 bzero (c->buckets, size);
1726 return c;
1727}
1728
1729
d3c35d17
CY
1730/* Find an image matching SPEC in the cache, and return it. If no
1731 image is found, return NULL. */
1732static struct image *
1733search_image_cache (f, spec, hash)
483e7ae0
CY
1734 struct frame *f;
1735 Lisp_Object spec;
d3c35d17 1736 unsigned hash;
483e7ae0 1737{
91be6b66 1738 struct image *img;
354884c4 1739 struct image_cache *c = FRAME_IMAGE_CACHE (f);
483e7ae0
CY
1740 int i = hash % IMAGE_CACHE_BUCKETS_SIZE;
1741
8198352b
CY
1742 if (!c) return NULL;
1743
d3c35d17
CY
1744 /* If the image spec does not specify a background color, the cached
1745 image must have the same background color as the current frame.
cf26ebe8
CY
1746 The foreground color must also match, for the sake of monochrome
1747 images.
1748
1749 In fact, we could ignore the foreground color matching condition
1750 for color images, or if the image spec specifies :foreground;
1751 similarly we could ignore the background color matching condition
1752 for formats that don't use transparency (such as jpeg), or if the
1753 image spec specifies :background. However, the extra memory
1754 usage is probably negligible in practice, so we don't bother. */
d3c35d17 1755
483e7ae0 1756 for (img = c->buckets[i]; img; img = img->next)
d3c35d17
CY
1757 if (img->hash == hash
1758 && !NILP (Fequal (img->spec, spec))
c5b8e0ea
YM
1759 && img->frame_foreground == FRAME_FOREGROUND_PIXEL (f)
1760 && img->frame_background == FRAME_BACKGROUND_PIXEL (f))
d3c35d17
CY
1761 break;
1762 return img;
1763}
1764
1765
1766/* Search frame F for an image with spec SPEC, and free it. */
1767
1768static void
1769uncache_image (f, spec)
1770 struct frame *f;
1771 Lisp_Object spec;
1772{
1773 struct image *img = search_image_cache (f, spec, sxhash (spec, 0));
1774 if (img)
1775 free_image (f, img);
483e7ae0
CY
1776}
1777
1778
4ef0d4d0
KS
1779/* Free image cache of frame F. Be aware that X frames share images
1780 caches. */
1781
1782void
1783free_image_cache (f)
1784 struct frame *f;
1785{
354884c4 1786 struct image_cache *c = FRAME_IMAGE_CACHE (f);
4ef0d4d0
KS
1787 if (c)
1788 {
1789 int i;
1790
1791 /* Cache should not be referenced by any frame when freed. */
1792 xassert (c->refcount == 0);
1793
1794 for (i = 0; i < c->used; ++i)
1795 free_image (f, c->images[i]);
1796 xfree (c->images);
1797 xfree (c->buckets);
1798 xfree (c);
354884c4 1799 FRAME_IMAGE_CACHE (f) = NULL;
4ef0d4d0
KS
1800 }
1801}
1802
1803
a2bc5bdd
SM
1804/* Clear image cache of frame F. FILTER=t means free all images.
1805 FILTER=nil means clear only images that haven't been
1806 displayed for some time.
1807 Else, only free the images which have FILTER in their `dependencies'.
1808 Should be called from time to time to reduce the number of loaded images.
1809 If image-cache-eviction-delay is non-nil, this frees images in the cache
1810 which weren't displayed for at least that many seconds. */
4ef0d4d0
KS
1811
1812void
a2bc5bdd 1813clear_image_cache (struct frame *f, Lisp_Object filter)
4ef0d4d0 1814{
354884c4 1815 struct image_cache *c = FRAME_IMAGE_CACHE (f);
4ef0d4d0 1816
a2bc5bdd 1817 if (c && (!NILP (filter) || INTEGERP (Vimage_cache_eviction_delay)))
4ef0d4d0
KS
1818 {
1819 EMACS_TIME t;
1820 unsigned long old;
1821 int i, nfreed;
1822
1823 EMACS_GET_TIME (t);
1824 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
1825
1826 /* Block input so that we won't be interrupted by a SIGIO
1827 while being in an inconsistent state. */
1828 BLOCK_INPUT;
1829
1830 for (i = nfreed = 0; i < c->used; ++i)
1831 {
1832 struct image *img = c->images[i];
1833 if (img != NULL
a2bc5bdd
SM
1834 && (NILP (filter) ? img->timestamp < old
1835 : (EQ (Qt, filter)
1836 || !NILP (Fmember (filter, img->dependencies)))))
4ef0d4d0
KS
1837 {
1838 free_image (f, img);
1839 ++nfreed;
1840 }
1841 }
1842
1843 /* We may be clearing the image cache because, for example,
1844 Emacs was iconified for a longer period of time. In that
1845 case, current matrices may still contain references to
1846 images freed above. So, clear these matrices. */
1847 if (nfreed)
1848 {
1849 Lisp_Object tail, frame;
1850
1851 FOR_EACH_FRAME (tail, frame)
1852 {
1853 struct frame *f = XFRAME (frame);
354884c4 1854 if (FRAME_IMAGE_CACHE (f) == c)
4ef0d4d0
KS
1855 clear_current_matrices (f);
1856 }
1857
1858 ++windows_or_buffers_changed;
1859 }
1860
1861 UNBLOCK_INPUT;
1862 }
1863}
1864
354884c4 1865void
a2bc5bdd 1866clear_image_caches (Lisp_Object filter)
354884c4
SM
1867{
1868 /* FIXME: We want to do
1869 * struct terminal *t;
1870 * for (t = terminal_list; t; t = t->next_terminal)
1871 * clear_image_cache (t, filter); */
1872 Lisp_Object tail, frame;
1873 FOR_EACH_FRAME (tail, frame)
1874 if (FRAME_WINDOW_P (XFRAME (frame)))
a2bc5bdd 1875 clear_image_cache (XFRAME (frame), filter);
354884c4 1876}
4ef0d4d0
KS
1877
1878DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
1879 0, 1, 0,
a2bc5bdd
SM
1880 doc: /* Clear the image cache.
1881FILTER nil or a frame means clear all images in the selected frame.
1882FILTER t means clear the image caches of all frames.
1883Anything else, means only clear those images which refer to FILTER,
1884which is then usually a filename. */)
1885 (filter)
1886 Lisp_Object filter;
4ef0d4d0 1887{
a2bc5bdd
SM
1888 if (!(EQ (filter, Qnil) || FRAMEP (filter)))
1889 clear_image_caches (filter);
4ef0d4d0 1890 else
a2bc5bdd 1891 clear_image_cache (check_x_frame (filter), Qt);
4ef0d4d0
KS
1892
1893 return Qnil;
1894}
1895
1896
483e7ae0
CY
1897DEFUN ("image-refresh", Fimage_refresh, Simage_refresh,
1898 1, 2, 0,
1899 doc: /* Refresh the image with specification SPEC on frame FRAME.
1900If SPEC specifies an image file, the displayed image is updated with
1901the current contents of that file.
1902FRAME nil or omitted means use the selected frame.
1903FRAME t means refresh the image on all frames. */)
1904 (spec, frame)
1905 Lisp_Object spec, frame;
1906{
1907 if (!valid_image_p (spec))
1908 error ("Invalid image specification");
1909
1910 if (EQ (frame, Qt))
1911 {
1912 Lisp_Object tail;
1913 FOR_EACH_FRAME (tail, frame)
1914 {
1915 struct frame *f = XFRAME (frame);
1916 if (FRAME_WINDOW_P (f))
1917 uncache_image (f, spec);
1918 }
1919 }
1920 else
1921 uncache_image (check_x_frame (frame), spec);
1922
1923 return Qnil;
1924}
1925
1926
4ef0d4d0
KS
1927/* Compute masks and transform image IMG on frame F, as specified
1928 by the image's specification, */
1929
1930static void
1931postprocess_image (f, img)
1932 struct frame *f;
1933 struct image *img;
1934{
1935 /* Manipulation of the image's mask. */
1936 if (img->pixmap)
1937 {
1938 Lisp_Object conversion, spec;
1939 Lisp_Object mask;
1940
1941 spec = img->spec;
1942
1943 /* `:heuristic-mask t'
1944 `:mask heuristic'
1945 means build a mask heuristically.
1946 `:heuristic-mask (R G B)'
1947 `:mask (heuristic (R G B))'
1948 means build a mask from color (R G B) in the
1949 image.
1950 `:mask nil'
1951 means remove a mask, if any. */
1952
1953 mask = image_spec_value (spec, QCheuristic_mask, NULL);
1954 if (!NILP (mask))
1955 x_build_heuristic_mask (f, img, mask);
1956 else
1957 {
1958 int found_p;
1959
1960 mask = image_spec_value (spec, QCmask, &found_p);
1961
1962 if (EQ (mask, Qheuristic))
1963 x_build_heuristic_mask (f, img, Qt);
1964 else if (CONSP (mask)
1965 && EQ (XCAR (mask), Qheuristic))
1966 {
1967 if (CONSP (XCDR (mask)))
1968 x_build_heuristic_mask (f, img, XCAR (XCDR (mask)));
1969 else
1970 x_build_heuristic_mask (f, img, XCDR (mask));
1971 }
1972 else if (NILP (mask) && found_p && img->mask)
1973 {
1974 Free_Pixmap (FRAME_X_DISPLAY (f), img->mask);
1975 img->mask = NO_PIXMAP;
1976 }
1977 }
1978
1979
1980 /* Should we apply an image transformation algorithm? */
1981 conversion = image_spec_value (spec, QCconversion, NULL);
1982 if (EQ (conversion, Qdisabled))
1983 x_disable_image (f, img);
1984 else if (EQ (conversion, Qlaplace))
1985 x_laplace (f, img);
1986 else if (EQ (conversion, Qemboss))
1987 x_emboss (f, img);
1988 else if (CONSP (conversion)
1989 && EQ (XCAR (conversion), Qedge_detection))
1990 {
1991 Lisp_Object tem;
1992 tem = XCDR (conversion);
1993 if (CONSP (tem))
1994 x_edge_detection (f, img,
1995 Fplist_get (tem, QCmatrix),
1996 Fplist_get (tem, QCcolor_adjustment));
1997 }
1998 }
1999}
2000
2001
2002/* Return the id of image with Lisp specification SPEC on frame F.
2003 SPEC must be a valid Lisp image specification (see valid_image_p). */
2004
2005int
2006lookup_image (f, spec)
2007 struct frame *f;
2008 Lisp_Object spec;
2009{
4a0e3f08 2010 struct image_cache *c;
4ef0d4d0 2011 struct image *img;
4ef0d4d0
KS
2012 unsigned hash;
2013 struct gcpro gcpro1;
2014 EMACS_TIME now;
2015
2016 /* F must be a window-system frame, and SPEC must be a valid image
2017 specification. */
2018 xassert (FRAME_WINDOW_P (f));
2019 xassert (valid_image_p (spec));
2020
354884c4 2021 c = FRAME_IMAGE_CACHE (f);
4a0e3f08 2022
4ef0d4d0
KS
2023 GCPRO1 (spec);
2024
2025 /* Look up SPEC in the hash table of the image cache. */
2026 hash = sxhash (spec, 0);
d3c35d17 2027 img = search_image_cache (f, spec, hash);
f1f25b99
CY
2028 if (img && img->load_failed_p)
2029 {
2030 free_image (f, img);
2031 img = NULL;
2032 }
2033
4ef0d4d0
KS
2034 /* If not found, create a new image and cache it. */
2035 if (img == NULL)
2036 {
2037 extern Lisp_Object Qpostscript;
2038
2039 BLOCK_INPUT;
2040 img = make_image (spec, hash);
2041 cache_image (f, img);
2042 img->load_failed_p = img->type->load (f, img) == 0;
c5b8e0ea
YM
2043 img->frame_foreground = FRAME_FOREGROUND_PIXEL (f);
2044 img->frame_background = FRAME_BACKGROUND_PIXEL (f);
4ef0d4d0
KS
2045
2046 /* If we can't load the image, and we don't have a width and
2047 height, use some arbitrary width and height so that we can
2048 draw a rectangle for it. */
2049 if (img->load_failed_p)
2050 {
2051 Lisp_Object value;
2052
2053 value = image_spec_value (spec, QCwidth, NULL);
2054 img->width = (INTEGERP (value)
2055 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
2056 value = image_spec_value (spec, QCheight, NULL);
2057 img->height = (INTEGERP (value)
2058 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
2059 }
2060 else
2061 {
2062 /* Handle image type independent image attributes
2063 `:ascent ASCENT', `:margin MARGIN', `:relief RELIEF',
2064 `:background COLOR'. */
2065 Lisp_Object ascent, margin, relief, bg;
2066
2067 ascent = image_spec_value (spec, QCascent, NULL);
2068 if (INTEGERP (ascent))
2069 img->ascent = XFASTINT (ascent);
2070 else if (EQ (ascent, Qcenter))
2071 img->ascent = CENTERED_IMAGE_ASCENT;
2072
2073 margin = image_spec_value (spec, QCmargin, NULL);
2074 if (INTEGERP (margin) && XINT (margin) >= 0)
2075 img->vmargin = img->hmargin = XFASTINT (margin);
2076 else if (CONSP (margin) && INTEGERP (XCAR (margin))
2077 && INTEGERP (XCDR (margin)))
2078 {
2079 if (XINT (XCAR (margin)) > 0)
2080 img->hmargin = XFASTINT (XCAR (margin));
2081 if (XINT (XCDR (margin)) > 0)
2082 img->vmargin = XFASTINT (XCDR (margin));
2083 }
2084
2085 relief = image_spec_value (spec, QCrelief, NULL);
2086 if (INTEGERP (relief))
2087 {
2088 img->relief = XINT (relief);
1ea40aa2
EZ
2089 img->hmargin += eabs (img->relief);
2090 img->vmargin += eabs (img->relief);
4ef0d4d0
KS
2091 }
2092
2093 if (! img->background_valid)
2094 {
2095 bg = image_spec_value (img->spec, QCbackground, NULL);
2096 if (!NILP (bg))
2097 {
2098 img->background
2099 = x_alloc_image_color (f, img, bg,
2100 FRAME_BACKGROUND_PIXEL (f));
2101 img->background_valid = 1;
2102 }
2103 }
2104
2105 /* Do image transformations and compute masks, unless we
2106 don't have the image yet. */
2107 if (!EQ (*img->type->type, Qpostscript))
2108 postprocess_image (f, img);
2109 }
2110
2111 UNBLOCK_INPUT;
2112 }
2113
2114 /* We're using IMG, so set its timestamp to `now'. */
2115 EMACS_GET_TIME (now);
2116 img->timestamp = EMACS_SECS (now);
2117
2118 UNGCPRO;
2119
2120 /* Value is the image id. */
2121 return img->id;
2122}
2123
2124
2125/* Cache image IMG in the image cache of frame F. */
2126
2127static void
2128cache_image (f, img)
2129 struct frame *f;
2130 struct image *img;
2131{
354884c4 2132 struct image_cache *c = FRAME_IMAGE_CACHE (f);
4ef0d4d0
KS
2133 int i;
2134
2135 /* Find a free slot in c->images. */
2136 for (i = 0; i < c->used; ++i)
2137 if (c->images[i] == NULL)
2138 break;
2139
2140 /* If no free slot found, maybe enlarge c->images. */
2141 if (i == c->used && c->used == c->size)
2142 {
2143 c->size *= 2;
2144 c->images = (struct image **) xrealloc (c->images,
2145 c->size * sizeof *c->images);
2146 }
2147
2148 /* Add IMG to c->images, and assign IMG an id. */
2149 c->images[i] = img;
2150 img->id = i;
2151 if (i == c->used)
2152 ++c->used;
2153
2154 /* Add IMG to the cache's hash table. */
2155 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
2156 img->next = c->buckets[i];
2157 if (img->next)
2158 img->next->prev = img;
2159 img->prev = NULL;
2160 c->buckets[i] = img;
2161}
2162
2163
2164/* Call FN on every image in the image cache of frame F. Used to mark
2165 Lisp Objects in the image cache. */
2166
354884c4
SM
2167/* Mark Lisp objects in image IMG. */
2168
2169static void
2170mark_image (img)
2171 struct image *img;
2172{
2173 mark_object (img->spec);
a2bc5bdd 2174 mark_object (img->dependencies);
354884c4
SM
2175
2176 if (!NILP (img->data.lisp_val))
2177 mark_object (img->data.lisp_val);
2178}
2179
2180
4ef0d4d0 2181void
354884c4 2182mark_image_cache (struct image_cache *c)
4ef0d4d0 2183{
354884c4 2184 if (c)
4ef0d4d0 2185 {
354884c4
SM
2186 int i;
2187 for (i = 0; i < c->used; ++i)
2188 if (c->images[i])
2189 mark_image (c->images[i]);
4ef0d4d0
KS
2190 }
2191}
2192
2193
2194\f
2195/***********************************************************************
9e2a2647 2196 X / NS / W32 support code
4ef0d4d0
KS
2197 ***********************************************************************/
2198
2199#ifdef HAVE_NTGUI
2200
2201/* Macro for defining functions that will be loaded from image DLLs. */
09e8eb5b 2202#define DEF_IMGLIB_FN(func) int (FAR CDECL *fn_##func)()
4ef0d4d0
KS
2203
2204/* Macro for loading those image functions from the library. */
2205#define LOAD_IMGLIB_FN(lib,func) { \
2206 fn_##func = (void *) GetProcAddress (lib, #func); \
2207 if (!fn_##func) return 0; \
2208 }
2209
0855eb52
JB
2210/* Load a DLL implementing an image type.
2211 The `image-library-alist' variable associates a symbol,
3046a84b 2212 identifying an image type, to a list of possible filenames.
0855eb52
JB
2213 The function returns NULL if no library could be loaded for
2214 the given image type, or if the library was previously loaded;
2215 else the handle of the DLL. */
2216static HMODULE
2217w32_delayed_load (Lisp_Object libraries, Lisp_Object type)
2218{
2219 HMODULE library = NULL;
2220
2221 if (CONSP (libraries) && NILP (Fassq (type, Vimage_type_cache)))
2222 {
2223 Lisp_Object dlls = Fassq (type, libraries);
2224
2225 if (CONSP (dlls))
2226 for (dlls = XCDR (dlls); CONSP (dlls); dlls = XCDR (dlls))
2227 {
2228 CHECK_STRING_CAR (dlls);
2229 if (library = LoadLibrary (SDATA (XCAR (dlls))))
2230 break;
2231 }
2232 }
2233
2234 return library;
2235}
2236
4ef0d4d0
KS
2237#endif /* HAVE_NTGUI */
2238
2239static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
2240 XImagePtr *, Pixmap *));
2241static void x_destroy_x_image P_ ((XImagePtr));
2242static void x_put_x_image P_ ((struct frame *, XImagePtr, Pixmap, int, int));
2243
2244
2245/* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
2246 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
2247 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
2248 via xmalloc. Print error messages via image_error if an error
2249 occurs. Value is non-zero if successful.
2250
2251 On W32, a DEPTH of zero signifies a 24 bit image, otherwise DEPTH
2252 should indicate the bit depth of the image. */
2253
2254static int
2255x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
2256 struct frame *f;
2257 int width, height, depth;
2258 XImagePtr *ximg;
2259 Pixmap *pixmap;
2260{
2261#ifdef HAVE_X_WINDOWS
2262 Display *display = FRAME_X_DISPLAY (f);
2263 Window window = FRAME_X_WINDOW (f);
2264 Screen *screen = FRAME_X_SCREEN (f);
2265
2266 xassert (interrupt_input_blocked);
2267
2268 if (depth <= 0)
2269 depth = DefaultDepthOfScreen (screen);
2270 *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
2271 depth, ZPixmap, 0, NULL, width, height,
2272 depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
2273 if (*ximg == NULL)
2274 {
2275 image_error ("Unable to allocate X image", Qnil, Qnil);
2276 return 0;
2277 }
2278
2279 /* Allocate image raster. */
2280 (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
2281
2282 /* Allocate a pixmap of the same size. */
2283 *pixmap = XCreatePixmap (display, window, width, height, depth);
2284 if (*pixmap == NO_PIXMAP)
2285 {
2286 x_destroy_x_image (*ximg);
2287 *ximg = NULL;
2288 image_error ("Unable to create X pixmap", Qnil, Qnil);
2289 return 0;
2290 }
2291
2292 return 1;
2293#endif /* HAVE_X_WINDOWS */
2294
2295#ifdef HAVE_NTGUI
2296
2297 BITMAPINFOHEADER *header;
2298 HDC hdc;
2299 int scanline_width_bits;
2300 int remainder;
2301 int palette_colors = 0;
2302
2303 if (depth == 0)
2304 depth = 24;
2305
2306 if (depth != 1 && depth != 4 && depth != 8
2307 && depth != 16 && depth != 24 && depth != 32)
2308 {
2309 image_error ("Invalid image bit depth specified", Qnil, Qnil);
2310 return 0;
2311 }
2312
2313 scanline_width_bits = width * depth;
2314 remainder = scanline_width_bits % 32;
2315
2316 if (remainder)
2317 scanline_width_bits += 32 - remainder;
2318
2319 /* Bitmaps with a depth less than 16 need a palette. */
2320 /* BITMAPINFO structure already contains the first RGBQUAD. */
2321 if (depth < 16)
2322 palette_colors = 1 << depth - 1;
2323
2324 *ximg = xmalloc (sizeof (XImage) + palette_colors * sizeof (RGBQUAD));
2325 if (*ximg == NULL)
2326 {
2327 image_error ("Unable to allocate memory for XImage", Qnil, Qnil);
2328 return 0;
2329 }
2330
2331 header = &((*ximg)->info.bmiHeader);
2332 bzero (&((*ximg)->info), sizeof (BITMAPINFO));
2333 header->biSize = sizeof (*header);
2334 header->biWidth = width;
2335 header->biHeight = -height; /* negative indicates a top-down bitmap. */
2336 header->biPlanes = 1;
2337 header->biBitCount = depth;
2338 header->biCompression = BI_RGB;
2339 header->biClrUsed = palette_colors;
2340
2341 /* TODO: fill in palette. */
2342 if (depth == 1)
2343 {
2344 (*ximg)->info.bmiColors[0].rgbBlue = 0;
2345 (*ximg)->info.bmiColors[0].rgbGreen = 0;
2346 (*ximg)->info.bmiColors[0].rgbRed = 0;
2347 (*ximg)->info.bmiColors[0].rgbReserved = 0;
2348 (*ximg)->info.bmiColors[1].rgbBlue = 255;
2349 (*ximg)->info.bmiColors[1].rgbGreen = 255;
2350 (*ximg)->info.bmiColors[1].rgbRed = 255;
2351 (*ximg)->info.bmiColors[1].rgbReserved = 0;
2352 }
2353
2354 hdc = get_frame_dc (f);
2355
2356 /* Create a DIBSection and raster array for the bitmap,
2357 and store its handle in *pixmap. */
2358 *pixmap = CreateDIBSection (hdc, &((*ximg)->info),
2359 (depth < 16) ? DIB_PAL_COLORS : DIB_RGB_COLORS,
2e09fef1
EZ
2360 /* casting avoids a GCC warning */
2361 (void **)&((*ximg)->data), NULL, 0);
4ef0d4d0
KS
2362
2363 /* Realize display palette and garbage all frames. */
2364 release_frame_dc (f, hdc);
2365
2366 if (*pixmap == NULL)
2367 {
5fc9fdeb 2368 DWORD err = GetLastError ();
4ef0d4d0
KS
2369 Lisp_Object errcode;
2370 /* All system errors are < 10000, so the following is safe. */
2371 XSETINT (errcode, (int) err);
2372 image_error ("Unable to create bitmap, error code %d", errcode, Qnil);
2373 x_destroy_x_image (*ximg);
2374 return 0;
2375 }
2376
2377 return 1;
2378
2379#endif /* HAVE_NTGUI */
2380
edfda783
AR
2381#ifdef HAVE_NS
2382 *pixmap = ns_image_for_XPM(width, height, depth);
2383 if (*pixmap == 0)
2384 {
2385 *ximg = NULL;
2386 image_error ("Unable to allocate NSImage for XPM pixmap", Qnil, Qnil);
2387 return 0;
2388 }
2389 *ximg = *pixmap;
2390 return 1;
2391#endif
4ef0d4d0
KS
2392}
2393
2394
2395/* Destroy XImage XIMG. Free XIMG->data. */
2396
2397static void
2398x_destroy_x_image (ximg)
2399 XImagePtr ximg;
2400{
2401 xassert (interrupt_input_blocked);
2402 if (ximg)
2403 {
2404#ifdef HAVE_X_WINDOWS
2405 xfree (ximg->data);
2406 ximg->data = NULL;
2407 XDestroyImage (ximg);
2408#endif /* HAVE_X_WINDOWS */
2409#ifdef HAVE_NTGUI
2410 /* Data will be freed by DestroyObject. */
2411 ximg->data = NULL;
2412 xfree (ximg);
2413#endif /* HAVE_NTGUI */
edfda783
AR
2414#ifdef HAVE_NS
2415 ns_release_object(ximg);
2416#endif /* HAVE_NS */
4ef0d4d0
KS
2417 }
2418}
2419
2420
2421/* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
2422 are width and height of both the image and pixmap. */
2423
2424static void
2425x_put_x_image (f, ximg, pixmap, width, height)
2426 struct frame *f;
2427 XImagePtr ximg;
2428 Pixmap pixmap;
2429 int width, height;
2430{
2431#ifdef HAVE_X_WINDOWS
2432 GC gc;
2433
2434 xassert (interrupt_input_blocked);
2435 gc = XCreateGC (FRAME_X_DISPLAY (f), pixmap, 0, NULL);
2436 XPutImage (FRAME_X_DISPLAY (f), pixmap, gc, ximg, 0, 0, 0, 0, width, height);
2437 XFreeGC (FRAME_X_DISPLAY (f), gc);
2438#endif /* HAVE_X_WINDOWS */
2439
2440#ifdef HAVE_NTGUI
2441#if 0 /* I don't think this is necessary looking at where it is used. */
2442 HDC hdc = get_frame_dc (f);
2443 SetDIBits (hdc, pixmap, 0, height, ximg->data, &(ximg->info), DIB_RGB_COLORS);
2444 release_frame_dc (f, hdc);
2445#endif
2446#endif /* HAVE_NTGUI */
2447
edfda783
AR
2448#ifdef HAVE_NS
2449 xassert (ximg == pixmap);
2450 ns_retain_object(ximg);
2451#endif
4ef0d4d0
KS
2452}
2453
2454\f
2455/***********************************************************************
2456 File Handling
2457 ***********************************************************************/
2458
4ef0d4d0
KS
2459static unsigned char *slurp_file P_ ((char *, int *));
2460
2461
6678dc11 2462/* Find image file FILE. Look in data-directory/images, then
022af124
KH
2463 x-bitmap-file-path. Value is the encoded full name of the file
2464 found, or nil if not found. */
4ef0d4d0 2465
c640aa9b 2466Lisp_Object
4ef0d4d0
KS
2467x_find_image_file (file)
2468 Lisp_Object file;
2469{
2470 Lisp_Object file_found, search_path;
2471 struct gcpro gcpro1, gcpro2;
2472 int fd;
2473
2474 file_found = Qnil;
6678dc11
GM
2475 /* TODO I think this should use something like image-load-path
2476 instead. Unfortunately, that can contain non-string elements. */
2477 search_path = Fcons (Fexpand_file_name (build_string ("images"),
2478 Vdata_directory),
2479 Vx_bitmap_file_path);
4ef0d4d0
KS
2480 GCPRO2 (file_found, search_path);
2481
050b82f6 2482 /* Try to find FILE in data-directory/images, then x-bitmap-file-path. */
4ef0d4d0
KS
2483 fd = openp (search_path, file, Qnil, &file_found, Qnil);
2484
2485 if (fd == -1)
2486 file_found = Qnil;
2487 else
022af124
KH
2488 {
2489 file_found = ENCODE_FILE (file_found);
2490 close (fd);
2491 }
4ef0d4d0
KS
2492
2493 UNGCPRO;
2494 return file_found;
2495}
2496
2497
2498/* Read FILE into memory. Value is a pointer to a buffer allocated
2499 with xmalloc holding FILE's contents. Value is null if an error
2500 occurred. *SIZE is set to the size of the file. */
2501
2502static unsigned char *
2503slurp_file (file, size)
2504 char *file;
2505 int *size;
2506{
2507 FILE *fp = NULL;
2508 unsigned char *buf = NULL;
2509 struct stat st;
2510
2511 if (stat (file, &st) == 0
2512 && (fp = fopen (file, "rb")) != NULL
fa8459a3 2513 && (buf = (unsigned char *) xmalloc (st.st_size),
4ef0d4d0
KS
2514 fread (buf, 1, st.st_size, fp) == st.st_size))
2515 {
2516 *size = st.st_size;
2517 fclose (fp);
2518 }
2519 else
2520 {
2521 if (fp)
2522 fclose (fp);
2523 if (buf)
2524 {
2525 xfree (buf);
2526 buf = NULL;
2527 }
2528 }
2529
2530 return buf;
2531}
2532
2533
2534\f
4ef0d4d0
KS
2535/***********************************************************************
2536 XBM images
2537 ***********************************************************************/
2538
2539static int xbm_scan P_ ((unsigned char **, unsigned char *, char *, int *));
2540static int xbm_load P_ ((struct frame *f, struct image *img));
2541static int xbm_load_image P_ ((struct frame *f, struct image *img,
2542 unsigned char *, unsigned char *));
2543static int xbm_image_p P_ ((Lisp_Object object));
f1f25b99
CY
2544static int xbm_read_bitmap_data P_ ((struct frame *f,
2545 unsigned char *, unsigned char *,
4ef0d4d0
KS
2546 int *, int *, unsigned char **));
2547static int xbm_file_p P_ ((Lisp_Object));
2548
2549
2550/* Indices of image specification fields in xbm_format, below. */
2551
2552enum xbm_keyword_index
2553{
2554 XBM_TYPE,
2555 XBM_FILE,
2556 XBM_WIDTH,
2557 XBM_HEIGHT,
2558 XBM_DATA,
2559 XBM_FOREGROUND,
2560 XBM_BACKGROUND,
2561 XBM_ASCENT,
2562 XBM_MARGIN,
2563 XBM_RELIEF,
2564 XBM_ALGORITHM,
2565 XBM_HEURISTIC_MASK,
2566 XBM_MASK,
2567 XBM_LAST
2568};
2569
2570/* Vector of image_keyword structures describing the format
2571 of valid XBM image specifications. */
2572
2573static struct image_keyword xbm_format[XBM_LAST] =
2574{
2575 {":type", IMAGE_SYMBOL_VALUE, 1},
2576 {":file", IMAGE_STRING_VALUE, 0},
2577 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
2578 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
2579 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
2580 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
2581 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
2582 {":ascent", IMAGE_ASCENT_VALUE, 0},
2583 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
2584 {":relief", IMAGE_INTEGER_VALUE, 0},
2585 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
2586 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
2587 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
2588};
2589
2590/* Structure describing the image type XBM. */
2591
2592static struct image_type xbm_type =
2593{
2594 &Qxbm,
2595 xbm_image_p,
2596 xbm_load,
2597 x_clear_image,
2598 NULL
2599};
2600
2601/* Tokens returned from xbm_scan. */
2602
2603enum xbm_token
2604{
2605 XBM_TK_IDENT = 256,
2606 XBM_TK_NUMBER
2607};
2608
2609
2610/* Return non-zero if OBJECT is a valid XBM-type image specification.
2611 A valid specification is a list starting with the symbol `image'
2612 The rest of the list is a property list which must contain an
2613 entry `:type xbm..
2614
2615 If the specification specifies a file to load, it must contain
2616 an entry `:file FILENAME' where FILENAME is a string.
2617
2618 If the specification is for a bitmap loaded from memory it must
2619 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
2620 WIDTH and HEIGHT are integers > 0. DATA may be:
2621
2622 1. a string large enough to hold the bitmap data, i.e. it must
2623 have a size >= (WIDTH + 7) / 8 * HEIGHT
2624
2625 2. a bool-vector of size >= WIDTH * HEIGHT
2626
2627 3. a vector of strings or bool-vectors, one for each line of the
2628 bitmap.
2629
bbe6f2aa 2630 4. a string containing an in-memory XBM file. WIDTH and HEIGHT
4ef0d4d0
KS
2631 may not be specified in this case because they are defined in the
2632 XBM file.
2633
2634 Both the file and data forms may contain the additional entries
2635 `:background COLOR' and `:foreground COLOR'. If not present,
2636 foreground and background of the frame on which the image is
2637 displayed is used. */
2638
2639static int
2640xbm_image_p (object)
2641 Lisp_Object object;
2642{
2643 struct image_keyword kw[XBM_LAST];
2644
2645 bcopy (xbm_format, kw, sizeof kw);
2646 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
2647 return 0;
2648
2649 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
2650
2651 if (kw[XBM_FILE].count)
2652 {
2653 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
2654 return 0;
2655 }
2656 else if (kw[XBM_DATA].count && xbm_file_p (kw[XBM_DATA].value))
2657 {
2658 /* In-memory XBM file. */
2659 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_FILE].count)
2660 return 0;
2661 }
2662 else
2663 {
2664 Lisp_Object data;
2665 int width, height;
2666
2667 /* Entries for `:width', `:height' and `:data' must be present. */
2668 if (!kw[XBM_WIDTH].count
2669 || !kw[XBM_HEIGHT].count
2670 || !kw[XBM_DATA].count)
2671 return 0;
2672
2673 data = kw[XBM_DATA].value;
2674 width = XFASTINT (kw[XBM_WIDTH].value);
2675 height = XFASTINT (kw[XBM_HEIGHT].value);
2676
2677 /* Check type of data, and width and height against contents of
2678 data. */
2679 if (VECTORP (data))
2680 {
2681 int i;
2682
2683 /* Number of elements of the vector must be >= height. */
2684 if (XVECTOR (data)->size < height)
2685 return 0;
2686
2687 /* Each string or bool-vector in data must be large enough
2688 for one line of the image. */
2689 for (i = 0; i < height; ++i)
2690 {
2691 Lisp_Object elt = XVECTOR (data)->contents[i];
2692
2693 if (STRINGP (elt))
2694 {
2695 if (SCHARS (elt)
2696 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
2697 return 0;
2698 }
2699 else if (BOOL_VECTOR_P (elt))
2700 {
2701 if (XBOOL_VECTOR (elt)->size < width)
2702 return 0;
2703 }
2704 else
2705 return 0;
2706 }
2707 }
2708 else if (STRINGP (data))
2709 {
2710 if (SCHARS (data)
2711 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
2712 return 0;
2713 }
2714 else if (BOOL_VECTOR_P (data))
2715 {
2716 if (XBOOL_VECTOR (data)->size < width * height)
2717 return 0;
2718 }
2719 else
2720 return 0;
2721 }
2722
2723 return 1;
2724}
2725
2726
2727/* Scan a bitmap file. FP is the stream to read from. Value is
2728 either an enumerator from enum xbm_token, or a character for a
2729 single-character token, or 0 at end of file. If scanning an
2730 identifier, store the lexeme of the identifier in SVAL. If
2731 scanning a number, store its value in *IVAL. */
2732
2733static int
2734xbm_scan (s, end, sval, ival)
2735 unsigned char **s, *end;
2736 char *sval;
2737 int *ival;
2738{
2739 unsigned int c;
2740
2741 loop:
2742
2743 /* Skip white space. */
2744 while (*s < end && (c = *(*s)++, isspace (c)))
2745 ;
2746
2747 if (*s >= end)
2748 c = 0;
2749 else if (isdigit (c))
2750 {
2751 int value = 0, digit;
2752
2753 if (c == '0' && *s < end)
2754 {
2755 c = *(*s)++;
2756 if (c == 'x' || c == 'X')
2757 {
2758 while (*s < end)
2759 {
2760 c = *(*s)++;
2761 if (isdigit (c))
2762 digit = c - '0';
2763 else if (c >= 'a' && c <= 'f')
2764 digit = c - 'a' + 10;
2765 else if (c >= 'A' && c <= 'F')
2766 digit = c - 'A' + 10;
2767 else
2768 break;
2769 value = 16 * value + digit;
2770 }
2771 }
2772 else if (isdigit (c))
2773 {
2774 value = c - '0';
2775 while (*s < end
2776 && (c = *(*s)++, isdigit (c)))
2777 value = 8 * value + c - '0';
2778 }
2779 }
2780 else
2781 {
2782 value = c - '0';
2783 while (*s < end
2784 && (c = *(*s)++, isdigit (c)))
2785 value = 10 * value + c - '0';
2786 }
2787
2788 if (*s < end)
2789 *s = *s - 1;
2790 *ival = value;
2791 c = XBM_TK_NUMBER;
2792 }
2793 else if (isalpha (c) || c == '_')
2794 {
2795 *sval++ = c;
2796 while (*s < end
2797 && (c = *(*s)++, (isalnum (c) || c == '_')))
2798 *sval++ = c;
2799 *sval = 0;
2800 if (*s < end)
2801 *s = *s - 1;
2802 c = XBM_TK_IDENT;
2803 }
2804 else if (c == '/' && **s == '*')
2805 {
2806 /* C-style comment. */
2807 ++*s;
2808 while (**s && (**s != '*' || *(*s + 1) != '/'))
2809 ++*s;
2810 if (**s)
2811 {
2812 *s += 2;
2813 goto loop;
2814 }
2815 }
2816
2817 return c;
2818}
2819
2820#ifdef HAVE_NTGUI
2821
2822/* Create a Windows bitmap from X bitmap data. */
2823static HBITMAP
2824w32_create_pixmap_from_bitmap_data (int width, int height, char *data)
2825{
2826 static unsigned char swap_nibble[16]
2827 = { 0x0, 0x8, 0x4, 0xc, /* 0000 1000 0100 1100 */
2828 0x2, 0xa, 0x6, 0xe, /* 0010 1010 0110 1110 */
2829 0x1, 0x9, 0x5, 0xd, /* 0001 1001 0101 1101 */
2830 0x3, 0xb, 0x7, 0xf }; /* 0011 1011 0111 1111 */
2831 int i, j, w1, w2;
2832 unsigned char *bits, *p;
2833 HBITMAP bmp;
2834
2835 w1 = (width + 7) / 8; /* nb of 8bits elt in X bitmap */
2836 w2 = ((width + 15) / 16) * 2; /* nb of 16bits elt in W32 bitmap */
2837 bits = (unsigned char *) alloca (height * w2);
2838 bzero (bits, height * w2);
2839 for (i = 0; i < height; i++)
2840 {
2841 p = bits + i*w2;
2842 for (j = 0; j < w1; j++)
2843 {
2844 /* Bitswap XBM bytes to match how Windows does things. */
2845 unsigned char c = *data++;
2846 *p++ = (unsigned char)((swap_nibble[c & 0xf] << 4)
2847 | (swap_nibble[(c>>4) & 0xf]));
2848 }
2849 }
2850 bmp = CreateBitmap (width, height, 1, 1, (char *) bits);
2851
2852 return bmp;
2853}
2854
3046a84b
JB
2855static void
2856convert_mono_to_color_image (f, img, foreground, background)
4ef0d4d0
KS
2857 struct frame *f;
2858 struct image *img;
2859 COLORREF foreground, background;
2860{
2861 HDC hdc, old_img_dc, new_img_dc;
2862 HGDIOBJ old_prev, new_prev;
2863 HBITMAP new_pixmap;
2864
2865 hdc = get_frame_dc (f);
2866 old_img_dc = CreateCompatibleDC (hdc);
2867 new_img_dc = CreateCompatibleDC (hdc);
2868 new_pixmap = CreateCompatibleBitmap (hdc, img->width, img->height);
2869 release_frame_dc (f, hdc);
2870 old_prev = SelectObject (old_img_dc, img->pixmap);
2871 new_prev = SelectObject (new_img_dc, new_pixmap);
44b1dc2e
JR
2872 /* Windows convention for mono bitmaps is black = background,
2873 white = foreground. */
2386b1f1
JR
2874 SetTextColor (new_img_dc, background);
2875 SetBkColor (new_img_dc, foreground);
4ef0d4d0
KS
2876
2877 BitBlt (new_img_dc, 0, 0, img->width, img->height, old_img_dc,
2878 0, 0, SRCCOPY);
2879
2880 SelectObject (old_img_dc, old_prev);
2881 SelectObject (new_img_dc, new_prev);
2882 DeleteDC (old_img_dc);
2883 DeleteDC (new_img_dc);
2884 DeleteObject (img->pixmap);
2885 if (new_pixmap == 0)
2886 fprintf (stderr, "Failed to convert image to color.\n");
2887 else
2888 img->pixmap = new_pixmap;
2889}
2890
2891#define XBM_BIT_SHUFFLE(b) (~(b))
2892
2893#else
2894
2895#define XBM_BIT_SHUFFLE(b) (b)
2896
2897#endif /* HAVE_NTGUI */
2898
2899
2900static void
3046a84b 2901Create_Pixmap_From_Bitmap_Data (f, img, data, fg, bg, non_default_colors)
4ef0d4d0
KS
2902 struct frame *f;
2903 struct image *img;
2904 char *data;
2905 RGB_PIXEL_COLOR fg, bg;
2906 int non_default_colors;
2907{
2908#ifdef HAVE_NTGUI
2909 img->pixmap
2910 = w32_create_pixmap_from_bitmap_data (img->width, img->height, data);
2911
2912 /* If colors were specified, transfer the bitmap to a color one. */
2913 if (non_default_colors)
2914 convert_mono_to_color_image (f, img, fg, bg);
edfda783
AR
2915
2916#elif defined (HAVE_NS)
2917 img->pixmap = ns_image_from_XBM(data, img->width, img->height);
2918
4ef0d4d0
KS
2919#else
2920 img->pixmap
2921 = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
2922 FRAME_X_WINDOW (f),
2923 data,
2924 img->width, img->height,
2925 fg, bg,
2926 DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
edfda783 2927#endif /* !HAVE_NTGUI && !HAVE_NS */
4ef0d4d0
KS
2928}
2929
2930
2931
2932/* Replacement for XReadBitmapFileData which isn't available under old
2933 X versions. CONTENTS is a pointer to a buffer to parse; END is the
2934 buffer's end. Set *WIDTH and *HEIGHT to the width and height of
2935 the image. Return in *DATA the bitmap data allocated with xmalloc.
2936 Value is non-zero if successful. DATA null means just test if
2937 CONTENTS looks like an in-memory XBM file. */
2938
2939static int
f1f25b99
CY
2940xbm_read_bitmap_data (f, contents, end, width, height, data)
2941 struct frame *f;
4ef0d4d0
KS
2942 unsigned char *contents, *end;
2943 int *width, *height;
2944 unsigned char **data;
2945{
2946 unsigned char *s = contents;
2947 char buffer[BUFSIZ];
2948 int padding_p = 0;
2949 int v10 = 0;
2950 int bytes_per_line, i, nbytes;
2951 unsigned char *p;
2952 int value;
2953 int LA1;
2954
2955#define match() \
2956 LA1 = xbm_scan (&s, end, buffer, &value)
2957
2958#define expect(TOKEN) \
2959 if (LA1 != (TOKEN)) \
2960 goto failure; \
2961 else \
2962 match ()
2963
2964#define expect_ident(IDENT) \
2965 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
2966 match (); \
2967 else \
2968 goto failure
2969
2970 *width = *height = -1;
2971 if (data)
2972 *data = NULL;
2973 LA1 = xbm_scan (&s, end, buffer, &value);
2974
2975 /* Parse defines for width, height and hot-spots. */
2976 while (LA1 == '#')
2977 {
2978 match ();
2979 expect_ident ("define");
2980 expect (XBM_TK_IDENT);
2981
431feaf6 2982 if (LA1 == XBM_TK_NUMBER)
4ef0d4d0
KS
2983 {
2984 char *p = strrchr (buffer, '_');
2985 p = p ? p + 1 : buffer;
2986 if (strcmp (p, "width") == 0)
2987 *width = value;
2988 else if (strcmp (p, "height") == 0)
2989 *height = value;
2990 }
2991 expect (XBM_TK_NUMBER);
2992 }
2993
f1f25b99 2994 if (!check_image_size (f, *width, *height))
4ef0d4d0
KS
2995 goto failure;
2996 else if (data == NULL)
2997 goto success;
2998
2999 /* Parse bits. Must start with `static'. */
3000 expect_ident ("static");
3001 if (LA1 == XBM_TK_IDENT)
3002 {
3003 if (strcmp (buffer, "unsigned") == 0)
3004 {
3005 match ();
3006 expect_ident ("char");
3007 }
3008 else if (strcmp (buffer, "short") == 0)
3009 {
3010 match ();
3011 v10 = 1;
3012 if (*width % 16 && *width % 16 < 9)
3013 padding_p = 1;
3014 }
3015 else if (strcmp (buffer, "char") == 0)
3016 match ();
3017 else
3018 goto failure;
3019 }
3020 else
3021 goto failure;
3022
3023 expect (XBM_TK_IDENT);
3024 expect ('[');
3025 expect (']');
3026 expect ('=');
3027 expect ('{');
3028
3029 bytes_per_line = (*width + 7) / 8 + padding_p;
3030 nbytes = bytes_per_line * *height;
fa8459a3 3031 p = *data = (unsigned char *) xmalloc (nbytes);
4ef0d4d0
KS
3032
3033 if (v10)
3034 {
3035 for (i = 0; i < nbytes; i += 2)
3036 {
3037 int val = value;
3038 expect (XBM_TK_NUMBER);
3039
3040 *p++ = XBM_BIT_SHUFFLE (val);
3041 if (!padding_p || ((i + 2) % bytes_per_line))
3042 *p++ = XBM_BIT_SHUFFLE (value >> 8);
3043
3044 if (LA1 == ',' || LA1 == '}')
3045 match ();
3046 else
3047 goto failure;
3048 }
3049 }
3050 else
3051 {
3052 for (i = 0; i < nbytes; ++i)
3053 {
3054 int val = value;
3055 expect (XBM_TK_NUMBER);
3056
3057 *p++ = XBM_BIT_SHUFFLE (val);
3058
3059 if (LA1 == ',' || LA1 == '}')
3060 match ();
3061 else
3062 goto failure;
3063 }
3064 }
3065
3066 success:
3067 return 1;
3068
3069 failure:
3070
3071 if (data && *data)
3072 {
3073 xfree (*data);
3074 *data = NULL;
3075 }
3076 return 0;
3077
3078#undef match
3079#undef expect
3080#undef expect_ident
3081}
3082
3083
3084/* Load XBM image IMG which will be displayed on frame F from buffer
3085 CONTENTS. END is the end of the buffer. Value is non-zero if
3086 successful. */
3087
3088static int
3089xbm_load_image (f, img, contents, end)
3090 struct frame *f;
3091 struct image *img;
3092 unsigned char *contents, *end;
3093{
3094 int rc;
3095 unsigned char *data;
3096 int success_p = 0;
3097
f1f25b99 3098 rc = xbm_read_bitmap_data (f, contents, end, &img->width, &img->height, &data);
4ef0d4d0
KS
3099 if (rc)
3100 {
3101 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
3102 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
3103 int non_default_colors = 0;
3104 Lisp_Object value;
3105
3106 xassert (img->width > 0 && img->height > 0);
3107
3108 /* Get foreground and background colors, maybe allocate colors. */
3109 value = image_spec_value (img->spec, QCforeground, NULL);
3110 if (!NILP (value))
3111 {
3112 foreground = x_alloc_image_color (f, img, value, foreground);
3113 non_default_colors = 1;
3114 }
3115 value = image_spec_value (img->spec, QCbackground, NULL);
3116 if (!NILP (value))
3117 {
3118 background = x_alloc_image_color (f, img, value, background);
3119 img->background = background;
3120 img->background_valid = 1;
3121 non_default_colors = 1;
3122 }
3123
1f026899 3124 Create_Pixmap_From_Bitmap_Data (f, img, data,
4ef0d4d0
KS
3125 foreground, background,
3126 non_default_colors);
3127 xfree (data);
3128
3129 if (img->pixmap == NO_PIXMAP)
3130 {
3131 x_clear_image (f, img);
3132 image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil);
3133 }
3134 else
3135 success_p = 1;
3136 }
3137 else
3138 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
3139
3140 return success_p;
3141}
3142
3143
3144/* Value is non-zero if DATA looks like an in-memory XBM file. */
3145
3146static int
3147xbm_file_p (data)
3148 Lisp_Object data;
3149{
3150 int w, h;
3151 return (STRINGP (data)
f1f25b99 3152 && xbm_read_bitmap_data (NULL, SDATA (data),
4ef0d4d0
KS
3153 (SDATA (data)
3154 + SBYTES (data)),
3155 &w, &h, NULL));
3156}
3157
3158
3159/* Fill image IMG which is used on frame F with pixmap data. Value is
3160 non-zero if successful. */
3161
3162static int
3163xbm_load (f, img)
3164 struct frame *f;
3165 struct image *img;
3166{
3167 int success_p = 0;
3168 Lisp_Object file_name;
3169
3170 xassert (xbm_image_p (img->spec));
3171
3172 /* If IMG->spec specifies a file name, create a non-file spec from it. */
3173 file_name = image_spec_value (img->spec, QCfile, NULL);
3174 if (STRINGP (file_name))
3175 {
3176 Lisp_Object file;
3177 unsigned char *contents;
3178 int size;
3179 struct gcpro gcpro1;
3180
3181 file = x_find_image_file (file_name);
3182 GCPRO1 (file);
3183 if (!STRINGP (file))
3184 {
3185 image_error ("Cannot find image file `%s'", file_name, Qnil);
3186 UNGCPRO;
3187 return 0;
3188 }
3189
3190 contents = slurp_file (SDATA (file), &size);
3191 if (contents == NULL)
3192 {
3193 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
3194 UNGCPRO;
3195 return 0;
3196 }
3197
3198 success_p = xbm_load_image (f, img, contents, contents + size);
3199 UNGCPRO;
3200 }
3201 else
3202 {
3203 struct image_keyword fmt[XBM_LAST];
3204 Lisp_Object data;
3205 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
3206 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
3207 int non_default_colors = 0;
3208 char *bits;
3209 int parsed_p;
3210 int in_memory_file_p = 0;
3211
3212 /* See if data looks like an in-memory XBM file. */
3213 data = image_spec_value (img->spec, QCdata, NULL);
3214 in_memory_file_p = xbm_file_p (data);
3215
3216 /* Parse the image specification. */
3217 bcopy (xbm_format, fmt, sizeof fmt);
3218 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
3219 xassert (parsed_p);
3220
3221 /* Get specified width, and height. */
3222 if (!in_memory_file_p)
3223 {
3224 img->width = XFASTINT (fmt[XBM_WIDTH].value);
3225 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
3226 xassert (img->width > 0 && img->height > 0);
3227 }
3228
3229 /* Get foreground and background colors, maybe allocate colors. */
3230 if (fmt[XBM_FOREGROUND].count
3231 && STRINGP (fmt[XBM_FOREGROUND].value))
3232 {
3233 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
3234 foreground);
3235 non_default_colors = 1;
3236 }
3237
3238 if (fmt[XBM_BACKGROUND].count
3239 && STRINGP (fmt[XBM_BACKGROUND].value))
3240 {
3241 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
3242 background);
3243 non_default_colors = 1;
3244 }
3245
3246 if (in_memory_file_p)
3247 success_p = xbm_load_image (f, img, SDATA (data),
3248 (SDATA (data)
3249 + SBYTES (data)));
3250 else
3251 {
3252 if (VECTORP (data))
3253 {
3254 int i;
3255 char *p;
3256 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
3257
3258 p = bits = (char *) alloca (nbytes * img->height);
3259 for (i = 0; i < img->height; ++i, p += nbytes)
3260 {
3261 Lisp_Object line = XVECTOR (data)->contents[i];
3262 if (STRINGP (line))
3263 bcopy (SDATA (line), p, nbytes);
3264 else
3265 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
3266 }
3267 }
3268 else if (STRINGP (data))
3269 bits = SDATA (data);
3270 else
3271 bits = XBOOL_VECTOR (data)->data;
3272
44b1dc2e
JR
3273#ifdef WINDOWSNT
3274 {
3275 char *invertedBits;
3276 int nbytes, i;
3277 /* Windows mono bitmaps are reversed compared with X. */
3278 invertedBits = bits;
3279 nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR
3280 * img->height;
3281 bits = (char *) alloca(nbytes);
3282 for (i = 0; i < nbytes; i++)
3283 bits[i] = XBM_BIT_SHUFFLE (invertedBits[i]);
3284 }
3285#endif
4ef0d4d0
KS
3286 /* Create the pixmap. */
3287
3288 Create_Pixmap_From_Bitmap_Data (f, img, bits,
3289 foreground, background,
3290 non_default_colors);
3291 if (img->pixmap)
3292 success_p = 1;
3293 else
3294 {
3295 image_error ("Unable to create pixmap for XBM image `%s'",
3296 img->spec, Qnil);
3297 x_clear_image (f, img);
3298 }
3299 }
3300 }
3301
3302 return success_p;
3303}
3304
3305
3306\f
3307/***********************************************************************
3308 XPM images
3309 ***********************************************************************/
3310
9e2a2647 3311#if defined (HAVE_XPM) || defined (HAVE_NS)
4ef0d4d0
KS
3312
3313static int xpm_image_p P_ ((Lisp_Object object));
3314static int xpm_load P_ ((struct frame *f, struct image *img));
3315static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
3316
9e2a2647 3317#endif /* HAVE_XPM || HAVE_NS */
ea1aaa6f
ST
3318
3319#ifdef HAVE_XPM
4ef0d4d0
KS
3320#ifdef HAVE_NTGUI
3321/* Indicate to xpm.h that we don't have Xlib. */
3322#define FOR_MSW
3323/* simx.h in xpm defines XColor and XImage differently than Emacs. */
279d3293 3324/* It also defines Display the same way as Emacs, but gcc 3.3 still barfs. */
4ef0d4d0
KS
3325#define XColor xpm_XColor
3326#define XImage xpm_XImage
279d3293 3327#define Display xpm_Display
4ef0d4d0
KS
3328#define PIXEL_ALREADY_TYPEDEFED
3329#include "X11/xpm.h"
3330#undef FOR_MSW
3331#undef XColor
3332#undef XImage
279d3293 3333#undef Display
4ef0d4d0
KS
3334#undef PIXEL_ALREADY_TYPEDEFED
3335#else
3336#include "X11/xpm.h"
3337#endif /* HAVE_NTGUI */
ea1aaa6f 3338#endif /* HAVE_XPM */
4ef0d4d0 3339
9e2a2647 3340#if defined (HAVE_XPM) || defined (HAVE_NS)
4ef0d4d0
KS
3341/* The symbol `xpm' identifying XPM-format images. */
3342
3343Lisp_Object Qxpm;
3344
3345/* Indices of image specification fields in xpm_format, below. */
3346
3347enum xpm_keyword_index
3348{
3349 XPM_TYPE,
3350 XPM_FILE,
3351 XPM_DATA,
3352 XPM_ASCENT,
3353 XPM_MARGIN,
3354 XPM_RELIEF,
3355 XPM_ALGORITHM,
3356 XPM_HEURISTIC_MASK,
3357 XPM_MASK,
3358 XPM_COLOR_SYMBOLS,
3359 XPM_BACKGROUND,
3360 XPM_LAST
3361};
3362
3363/* Vector of image_keyword structures describing the format
3364 of valid XPM image specifications. */
3365
3366static struct image_keyword xpm_format[XPM_LAST] =
3367{
3368 {":type", IMAGE_SYMBOL_VALUE, 1},
3369 {":file", IMAGE_STRING_VALUE, 0},
3370 {":data", IMAGE_STRING_VALUE, 0},
3371 {":ascent", IMAGE_ASCENT_VALUE, 0},
3372 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
3373 {":relief", IMAGE_INTEGER_VALUE, 0},
3374 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3375 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3376 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3377 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3378 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
3379};
3380
3381/* Structure describing the image type XPM. */
3382
3383static struct image_type xpm_type =
3384{
3385 &Qxpm,
3386 xpm_image_p,
3387 xpm_load,
3388 x_clear_image,
3389 NULL
3390};
3391
3392#ifdef HAVE_X_WINDOWS
3393
3394/* Define ALLOC_XPM_COLORS if we can use Emacs' own color allocation
3395 functions for allocating image colors. Our own functions handle
3396 color allocation failures more gracefully than the ones on the XPM
3397 lib. */
3398
3399#if defined XpmAllocColor && defined XpmFreeColors && defined XpmColorClosure
3400#define ALLOC_XPM_COLORS
3401#endif
3402#endif /* HAVE_X_WINDOWS */
3403
3404#ifdef ALLOC_XPM_COLORS
3405
3406static void xpm_init_color_cache P_ ((struct frame *, XpmAttributes *));
3407static void xpm_free_color_cache P_ ((void));
3408static int xpm_lookup_color P_ ((struct frame *, char *, XColor *));
3409static int xpm_color_bucket P_ ((char *));
3410static struct xpm_cached_color *xpm_cache_color P_ ((struct frame *, char *,
3411 XColor *, int));
3412
3413/* An entry in a hash table used to cache color definitions of named
3414 colors. This cache is necessary to speed up XPM image loading in
3415 case we do color allocations ourselves. Without it, we would need
3416 a call to XParseColor per pixel in the image. */
3417
3418struct xpm_cached_color
3419{
3420 /* Next in collision chain. */
3421 struct xpm_cached_color *next;
3422
3423 /* Color definition (RGB and pixel color). */
3424 XColor color;
3425
3426 /* Color name. */
3427 char name[1];
3428};
3429
3430/* The hash table used for the color cache, and its bucket vector
3431 size. */
3432
3433#define XPM_COLOR_CACHE_BUCKETS 1001
3434struct xpm_cached_color **xpm_color_cache;
3435
3436/* Initialize the color cache. */
3437
3438static void
3439xpm_init_color_cache (f, attrs)
3440 struct frame *f;
3441 XpmAttributes *attrs;
3442{
3443 size_t nbytes = XPM_COLOR_CACHE_BUCKETS * sizeof *xpm_color_cache;
3444 xpm_color_cache = (struct xpm_cached_color **) xmalloc (nbytes);
3445 memset (xpm_color_cache, 0, nbytes);
3446 init_color_table ();
3447
3448 if (attrs->valuemask & XpmColorSymbols)
3449 {
3450 int i;
3451 XColor color;
3452
3453 for (i = 0; i < attrs->numsymbols; ++i)
3454 if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
3455 attrs->colorsymbols[i].value, &color))
3456 {
3457 color.pixel = lookup_rgb_color (f, color.red, color.green,
3458 color.blue);
3459 xpm_cache_color (f, attrs->colorsymbols[i].name, &color, -1);
3460 }
3461 }
3462}
3463
3464/* Free the color cache. */
3465
3466static void
3467xpm_free_color_cache ()
3468{
3469 struct xpm_cached_color *p, *next;
3470 int i;
3471
3472 for (i = 0; i < XPM_COLOR_CACHE_BUCKETS; ++i)
3473 for (p = xpm_color_cache[i]; p; p = next)
3474 {
3475 next = p->next;
3476 xfree (p);
3477 }
3478
3479 xfree (xpm_color_cache);
3480 xpm_color_cache = NULL;
3481 free_color_table ();
3482}
3483
3484/* Return the bucket index for color named COLOR_NAME in the color
3485 cache. */
3486
3487static int
3488xpm_color_bucket (color_name)
3489 char *color_name;
3490{
3491 unsigned h = 0;
3492 char *s;
3493
3494 for (s = color_name; *s; ++s)
3495 h = (h << 2) ^ *s;
3496 return h %= XPM_COLOR_CACHE_BUCKETS;
3497}
3498
3499
3500/* On frame F, cache values COLOR for color with name COLOR_NAME.
3501 BUCKET, if >= 0, is a precomputed bucket index. Value is the cache
3502 entry added. */
3503
3504static struct xpm_cached_color *
3505xpm_cache_color (f, color_name, color, bucket)
3506 struct frame *f;
3507 char *color_name;
3508 XColor *color;
3509 int bucket;
3510{
3511 size_t nbytes;
3512 struct xpm_cached_color *p;
3513
3514 if (bucket < 0)
3515 bucket = xpm_color_bucket (color_name);
3516
3517 nbytes = sizeof *p + strlen (color_name);
3518 p = (struct xpm_cached_color *) xmalloc (nbytes);
3519 strcpy (p->name, color_name);
3520 p->color = *color;
3521 p->next = xpm_color_cache[bucket];
3522 xpm_color_cache[bucket] = p;
3523 return p;
3524}
3525
3526/* Look up color COLOR_NAME for frame F in the color cache. If found,
3527 return the cached definition in *COLOR. Otherwise, make a new
3528 entry in the cache and allocate the color. Value is zero if color
3529 allocation failed. */
3530
3531static int
3532xpm_lookup_color (f, color_name, color)
3533 struct frame *f;
3534 char *color_name;
3535 XColor *color;
3536{
3537 struct xpm_cached_color *p;
3538 int h = xpm_color_bucket (color_name);
3539
3540 for (p = xpm_color_cache[h]; p; p = p->next)
3541 if (strcmp (p->name, color_name) == 0)
3542 break;
3543
3544 if (p != NULL)
3545 *color = p->color;
3546 else if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
3547 color_name, color))
3548 {
3549 color->pixel = lookup_rgb_color (f, color->red, color->green,
3550 color->blue);
3551 p = xpm_cache_color (f, color_name, color, h);
3552 }
3553 /* You get `opaque' at least from ImageMagick converting pbm to xpm
3554 with transparency, and it's useful. */
3555 else if (strcmp ("opaque", color_name) == 0)
3556 {
3557 bzero (color, sizeof (XColor)); /* Is this necessary/correct? */
3558 color->pixel = FRAME_FOREGROUND_PIXEL (f);
3559 p = xpm_cache_color (f, color_name, color, h);
3560 }
3561
3562 return p != NULL;
3563}
3564
3565
3566/* Callback for allocating color COLOR_NAME. Called from the XPM lib.
3567 CLOSURE is a pointer to the frame on which we allocate the
3568 color. Return in *COLOR the allocated color. Value is non-zero
3569 if successful. */
3570
3571static int
3572xpm_alloc_color (dpy, cmap, color_name, color, closure)
3573 Display *dpy;
3574 Colormap cmap;
3575 char *color_name;
3576 XColor *color;
3577 void *closure;
3578{
3579 return xpm_lookup_color ((struct frame *) closure, color_name, color);
3580}
3581
3582
3583/* Callback for freeing NPIXELS colors contained in PIXELS. CLOSURE
3584 is a pointer to the frame on which we allocate the color. Value is
3585 non-zero if successful. */
3586
3587static int
3588xpm_free_colors (dpy, cmap, pixels, npixels, closure)
3589 Display *dpy;
3590 Colormap cmap;
3591 Pixel *pixels;
3592 int npixels;
3593 void *closure;
3594{
3595 return 1;
3596}
3597
3598#endif /* ALLOC_XPM_COLORS */
3599
3600
3601#ifdef HAVE_NTGUI
3602
3603/* XPM library details. */
3604
3605DEF_IMGLIB_FN (XpmFreeAttributes);
3606DEF_IMGLIB_FN (XpmCreateImageFromBuffer);
3607DEF_IMGLIB_FN (XpmReadFileToImage);
3608DEF_IMGLIB_FN (XImageFree);
3609
4ef0d4d0 3610static int
0855eb52 3611init_xpm_functions (Lisp_Object libraries)
4ef0d4d0
KS
3612{
3613 HMODULE library;
3614
0855eb52 3615 if (!(library = w32_delayed_load (libraries, Qxpm)))
4ef0d4d0
KS
3616 return 0;
3617
3618 LOAD_IMGLIB_FN (library, XpmFreeAttributes);
3619 LOAD_IMGLIB_FN (library, XpmCreateImageFromBuffer);
3620 LOAD_IMGLIB_FN (library, XpmReadFileToImage);
3621 LOAD_IMGLIB_FN (library, XImageFree);
3622 return 1;
3623}
3624
3625#endif /* HAVE_NTGUI */
3626
3627
3628/* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
3629 for XPM images. Such a list must consist of conses whose car and
3630 cdr are strings. */
3631
3632static int
3633xpm_valid_color_symbols_p (color_symbols)
3634 Lisp_Object color_symbols;
3635{
3636 while (CONSP (color_symbols))
3637 {
3638 Lisp_Object sym = XCAR (color_symbols);
3639 if (!CONSP (sym)
3640 || !STRINGP (XCAR (sym))
3641 || !STRINGP (XCDR (sym)))
3642 break;
3643 color_symbols = XCDR (color_symbols);
3644 }
3645
3646 return NILP (color_symbols);
3647}
3648
3649
3650/* Value is non-zero if OBJECT is a valid XPM image specification. */
3651
3652static int
3653xpm_image_p (object)
3654 Lisp_Object object;
3655{
3656 struct image_keyword fmt[XPM_LAST];
3657 bcopy (xpm_format, fmt, sizeof fmt);
3658 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
3659 /* Either `:file' or `:data' must be present. */
3660 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
3661 /* Either no `:color-symbols' or it's a list of conses
3662 whose car and cdr are strings. */
3663 && (fmt[XPM_COLOR_SYMBOLS].count == 0
3664 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value)));
3665}
3666
9e2a2647 3667#endif /* HAVE_XPM || HAVE_NS */
4ef0d4d0 3668
786a43d6
CY
3669#if defined (HAVE_XPM) && defined (HAVE_X_WINDOWS)
3670int
3671x_create_bitmap_from_xpm_data (f, bits)
3672 struct frame *f;
3673 char **bits;
3674{
3675 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3676 int id, rc;
3677 XpmAttributes attrs;
3678 Pixmap bitmap, mask;
3679
3680 bzero (&attrs, sizeof attrs);
3681
54188d8f
CY
3682 attrs.visual = FRAME_X_VISUAL (f);
3683 attrs.colormap = FRAME_X_COLORMAP (f);
3684 attrs.valuemask |= XpmVisual;
3685 attrs.valuemask |= XpmColormap;
3686
786a43d6
CY
3687 rc = XpmCreatePixmapFromData (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
3688 bits, &bitmap, &mask, &attrs);
3689 if (rc != XpmSuccess)
fe45ad15
CY
3690 {
3691 XpmFreeAttributes (&attrs);
3692 return -1;
3693 }
786a43d6
CY
3694
3695 id = x_allocate_bitmap_record (f);
786a43d6
CY
3696 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
3697 dpyinfo->bitmaps[id - 1].have_mask = 1;
3698 dpyinfo->bitmaps[id - 1].mask = mask;
3699 dpyinfo->bitmaps[id - 1].file = NULL;
3700 dpyinfo->bitmaps[id - 1].height = attrs.height;
3701 dpyinfo->bitmaps[id - 1].width = attrs.width;
3702 dpyinfo->bitmaps[id - 1].depth = attrs.depth;
3703 dpyinfo->bitmaps[id - 1].refcount = 1;
3704
3705 XpmFreeAttributes (&attrs);
3706 return id;
3707}
0d876a14 3708#endif /* defined (HAVE_XPM) && defined (HAVE_X_WINDOWS) */
786a43d6 3709
4ef0d4d0
KS
3710/* Load image IMG which will be displayed on frame F. Value is
3711 non-zero if successful. */
3712
ea1aaa6f
ST
3713#ifdef HAVE_XPM
3714
4ef0d4d0
KS
3715static int
3716xpm_load (f, img)
3717 struct frame *f;
3718 struct image *img;
3719{
3720 int rc;
3721 XpmAttributes attrs;
3722 Lisp_Object specified_file, color_symbols;
3723#ifdef HAVE_NTGUI
3724 HDC hdc;
3725 xpm_XImage * xpm_image = NULL, * xpm_mask = NULL;
3726#endif /* HAVE_NTGUI */
3727
3728 /* Configure the XPM lib. Use the visual of frame F. Allocate
3729 close colors. Return colors allocated. */
3730 bzero (&attrs, sizeof attrs);
3731
3732#ifndef HAVE_NTGUI
3733 attrs.visual = FRAME_X_VISUAL (f);
3734 attrs.colormap = FRAME_X_COLORMAP (f);
3735 attrs.valuemask |= XpmVisual;
3736 attrs.valuemask |= XpmColormap;
3737#endif /* HAVE_NTGUI */
3738
3739#ifdef ALLOC_XPM_COLORS
3740 /* Allocate colors with our own functions which handle
3741 failing color allocation more gracefully. */
3742 attrs.color_closure = f;
3743 attrs.alloc_color = xpm_alloc_color;
3744 attrs.free_colors = xpm_free_colors;
3745 attrs.valuemask |= XpmAllocColor | XpmFreeColors | XpmColorClosure;
3746#else /* not ALLOC_XPM_COLORS */
3747 /* Let the XPM lib allocate colors. */
3748 attrs.valuemask |= XpmReturnAllocPixels;
3749#ifdef XpmAllocCloseColors
3750 attrs.alloc_close_colors = 1;
3751 attrs.valuemask |= XpmAllocCloseColors;
3752#else /* not XpmAllocCloseColors */
3753 attrs.closeness = 600;
3754 attrs.valuemask |= XpmCloseness;
3755#endif /* not XpmAllocCloseColors */
3756#endif /* ALLOC_XPM_COLORS */
3757
3758 /* If image specification contains symbolic color definitions, add
3759 these to `attrs'. */
3760 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
3761 if (CONSP (color_symbols))
3762 {
3763 Lisp_Object tail;
3764 XpmColorSymbol *xpm_syms;
3765 int i, size;
3766
3767 attrs.valuemask |= XpmColorSymbols;
3768
3769 /* Count number of symbols. */
3770 attrs.numsymbols = 0;
3771 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
3772 ++attrs.numsymbols;
3773
3774 /* Allocate an XpmColorSymbol array. */
3775 size = attrs.numsymbols * sizeof *xpm_syms;
3776 xpm_syms = (XpmColorSymbol *) alloca (size);
3777 bzero (xpm_syms, size);
3778 attrs.colorsymbols = xpm_syms;
3779
3780 /* Fill the color symbol array. */
3781 for (tail = color_symbols, i = 0;
3782 CONSP (tail);
3783 ++i, tail = XCDR (tail))
3784 {
3785 Lisp_Object name = XCAR (XCAR (tail));
3786 Lisp_Object color = XCDR (XCAR (tail));
3787 xpm_syms[i].name = (char *) alloca (SCHARS (name) + 1);
3788 strcpy (xpm_syms[i].name, SDATA (name));
3789 xpm_syms[i].value = (char *) alloca (SCHARS (color) + 1);
3790 strcpy (xpm_syms[i].value, SDATA (color));
3791 }
3792 }
3793
3794 /* Create a pixmap for the image, either from a file, or from a
3795 string buffer containing data in the same format as an XPM file. */
3796#ifdef ALLOC_XPM_COLORS
3797 xpm_init_color_cache (f, &attrs);
3798#endif
3799
3800 specified_file = image_spec_value (img->spec, QCfile, NULL);
3801
3802#ifdef HAVE_NTGUI
3803 {
3804 HDC frame_dc = get_frame_dc (f);
3805 hdc = CreateCompatibleDC (frame_dc);
3806 release_frame_dc (f, frame_dc);
3807 }
3808#endif /* HAVE_NTGUI */
3809
3810 if (STRINGP (specified_file))
3811 {
3812 Lisp_Object file = x_find_image_file (specified_file);
3813 if (!STRINGP (file))
3814 {
3815 image_error ("Cannot find image file `%s'", specified_file, Qnil);
3816 return 0;
3817 }
3818
3819#ifdef HAVE_NTGUI
3820 /* XpmReadFileToPixmap is not available in the Windows port of
3821 libxpm. But XpmReadFileToImage almost does what we want. */
3822 rc = fn_XpmReadFileToImage (&hdc, SDATA (file),
3823 &xpm_image, &xpm_mask,
3824 &attrs);
3825#else
3826 rc = XpmReadFileToPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
3827 SDATA (file), &img->pixmap, &img->mask,
3828 &attrs);
3829#endif /* HAVE_NTGUI */
3830 }
3831 else
3832 {
3833 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
3834#ifdef HAVE_NTGUI
3835 /* XpmCreatePixmapFromBuffer is not available in the Windows port
3836 of libxpm. But XpmCreateImageFromBuffer almost does what we want. */
3837 rc = fn_XpmCreateImageFromBuffer (&hdc, SDATA (buffer),
3838 &xpm_image, &xpm_mask,
3839 &attrs);
3840#else
3841 rc = XpmCreatePixmapFromBuffer (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
3842 SDATA (buffer),
3843 &img->pixmap, &img->mask,
3844 &attrs);
3845#endif /* HAVE_NTGUI */
3846 }
3847
3848 if (rc == XpmSuccess)
3849 {
3850#if defined (COLOR_TABLE_SUPPORT) && defined (ALLOC_XPM_COLORS)
3851 img->colors = colors_in_color_table (&img->ncolors);
3852#else /* not ALLOC_XPM_COLORS */
3853 int i;
3854
3855#ifdef HAVE_NTGUI
3856 /* W32 XPM uses XImage to wrap what W32 Emacs calls a Pixmap,
3857 plus some duplicate attributes. */
3858 if (xpm_image && xpm_image->bitmap)
3859 {
3860 img->pixmap = xpm_image->bitmap;
3861 /* XImageFree in libXpm frees XImage struct without destroying
3862 the bitmap, which is what we want. */
3863 fn_XImageFree (xpm_image);
3864 }
3865 if (xpm_mask && xpm_mask->bitmap)
3866 {
3867 /* The mask appears to be inverted compared with what we expect.
3868 TODO: invert our expectations. See other places where we
3869 have to invert bits because our idea of masks is backwards. */
3870 HGDIOBJ old_obj;
3871 old_obj = SelectObject (hdc, xpm_mask->bitmap);
3872
3873 PatBlt (hdc, 0, 0, xpm_mask->width, xpm_mask->height, DSTINVERT);
3874 SelectObject (hdc, old_obj);
3875
3876 img->mask = xpm_mask->bitmap;
3877 fn_XImageFree (xpm_mask);
3878 DeleteDC (hdc);
3879 }
3880
3881 DeleteDC (hdc);
3882#endif /* HAVE_NTGUI */
3883
3884 /* Remember allocated colors. */
3885 img->ncolors = attrs.nalloc_pixels;
3886 img->colors = (unsigned long *) xmalloc (img->ncolors
3887 * sizeof *img->colors);
3888 for (i = 0; i < attrs.nalloc_pixels; ++i)
3889 {
3890 img->colors[i] = attrs.alloc_pixels[i];
3891#ifdef DEBUG_X_COLORS
3892 register_color (img->colors[i]);
3893#endif
3894 }
3895#endif /* not ALLOC_XPM_COLORS */
3896
3897 img->width = attrs.width;
3898 img->height = attrs.height;
3899 xassert (img->width > 0 && img->height > 0);
3900
3901 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
3902#ifdef HAVE_NTGUI
3903 fn_XpmFreeAttributes (&attrs);
3904#else
3905 XpmFreeAttributes (&attrs);
3906#endif /* HAVE_NTGUI */
3907 }
3908 else
3909 {
3910#ifdef HAVE_NTGUI
3911 DeleteDC (hdc);
3912#endif /* HAVE_NTGUI */
3913
3914 switch (rc)
3915 {
3916 case XpmOpenFailed:
3917 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
3918 break;
3919
3920 case XpmFileInvalid:
3921 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
3922 break;
3923
3924 case XpmNoMemory:
3925 image_error ("Out of memory (%s)", img->spec, Qnil);
3926 break;
3927
3928 case XpmColorFailed:
3929 image_error ("Color allocation error (%s)", img->spec, Qnil);
3930 break;
3931
3932 default:
3933 image_error ("Unknown error (%s)", img->spec, Qnil);
3934 break;
3935 }
3936 }
3937
3938#ifdef ALLOC_XPM_COLORS
3939 xpm_free_color_cache ();
3940#endif
3941 return rc == XpmSuccess;
3942}
3943
3944#endif /* HAVE_XPM */
3945
9e2a2647 3946#if defined (HAVE_NS) && !defined (HAVE_XPM)
ea1aaa6f 3947
9e2a2647 3948/* XPM support functions for NS where libxpm is not available.
ea1aaa6f
ST
3949 Only XPM version 3 (without any extensions) is supported. */
3950
46accb8f
YM
3951static int xpm_scan P_ ((const unsigned char **, const unsigned char *,
3952 const unsigned char **, int *));
ea1aaa6f 3953static Lisp_Object xpm_make_color_table_v
46accb8f
YM
3954 P_ ((void (**) (Lisp_Object, const unsigned char *, int, Lisp_Object),
3955 Lisp_Object (**) (Lisp_Object, const unsigned char *, int)));
3956static void xpm_put_color_table_v P_ ((Lisp_Object, const unsigned char *,
9ecf6403 3957 int, Lisp_Object));
ea1aaa6f 3958static Lisp_Object xpm_get_color_table_v P_ ((Lisp_Object,
46accb8f 3959 const unsigned char *, int));
ea1aaa6f 3960static Lisp_Object xpm_make_color_table_h
46accb8f
YM
3961 P_ ((void (**) (Lisp_Object, const unsigned char *, int, Lisp_Object),
3962 Lisp_Object (**) (Lisp_Object, const unsigned char *, int)));
3963static void xpm_put_color_table_h P_ ((Lisp_Object, const unsigned char *,
9ecf6403 3964 int, Lisp_Object));
ea1aaa6f 3965static Lisp_Object xpm_get_color_table_h P_ ((Lisp_Object,
46accb8f
YM
3966 const unsigned char *, int));
3967static int xpm_str_to_color_key P_ ((const char *));
ea1aaa6f 3968static int xpm_load_image P_ ((struct frame *, struct image *,
46accb8f 3969 const unsigned char *, const unsigned char *));
ea1aaa6f
ST
3970
3971/* Tokens returned from xpm_scan. */
3972
3973enum xpm_token
3974{
3975 XPM_TK_IDENT = 256,
3976 XPM_TK_STRING,
3977 XPM_TK_EOF
3978};
3979
3980/* Scan an XPM data and return a character (< 256) or a token defined
3981 by enum xpm_token above. *S and END are the start (inclusive) and
3982 the end (exclusive) addresses of the data, respectively. Advance
3983 *S while scanning. If token is either XPM_TK_IDENT or
3984 XPM_TK_STRING, *BEG and *LEN are set to the start address and the
3985 length of the corresponding token, respectively. */
3986
3987static int
3988xpm_scan (s, end, beg, len)
46accb8f 3989 const unsigned char **s, *end, **beg;
ea1aaa6f
ST
3990 int *len;
3991{
3992 int c;
3993
3994 while (*s < end)
3995 {
3996 /* Skip white-space. */
3997 while (*s < end && (c = *(*s)++, isspace (c)))
9ecf6403 3998 ;
ea1aaa6f
ST
3999
4000 /* gnus-pointer.xpm uses '-' in its identifier.
9ecf6403 4001 sb-dir-plus.xpm uses '+' in its identifier. */
ea1aaa6f 4002 if (isalpha (c) || c == '_' || c == '-' || c == '+')
9ecf6403
YM
4003 {
4004 *beg = *s - 1;
2ff0845e
YM
4005 while (*s < end
4006 && (c = **s, isalnum (c) || c == '_' || c == '-' || c == '+'))
9ecf6403
YM
4007 ++*s;
4008 *len = *s - *beg;
4009 return XPM_TK_IDENT;
4010 }
ea1aaa6f 4011 else if (c == '"')
9ecf6403
YM
4012 {
4013 *beg = *s;
4014 while (*s < end && **s != '"')
4015 ++*s;
4016 *len = *s - *beg;
4017 if (*s < end)
4018 ++*s;
4019 return XPM_TK_STRING;
4020 }
ea1aaa6f 4021 else if (c == '/')
9ecf6403
YM
4022 {
4023 if (*s < end && **s == '*')
4024 {
4025 /* C-style comment. */
4026 ++*s;
4027 do
4028 {
4029 while (*s < end && *(*s)++ != '*')
4030 ;
4031 }
4032 while (*s < end && **s != '/');
4033 if (*s < end)
4034 ++*s;
4035 }
4036 else
4037 return c;
4038 }
ea1aaa6f 4039 else
9ecf6403 4040 return c;
ea1aaa6f
ST
4041 }
4042
4043 return XPM_TK_EOF;
4044}
4045
bbe6f2aa 4046/* Functions for color table lookup in XPM data. A key is a string
ea1aaa6f
ST
4047 specifying the color of each pixel in XPM data. A value is either
4048 an integer that specifies a pixel color, Qt that specifies
4049 transparency, or Qnil for the unspecified color. If the length of
4050 the key string is one, a vector is used as a table. Otherwise, a
4051 hash table is used. */
4052
4053static Lisp_Object
4054xpm_make_color_table_v (put_func, get_func)
46accb8f
YM
4055 void (**put_func) (Lisp_Object, const unsigned char *, int, Lisp_Object);
4056 Lisp_Object (**get_func) (Lisp_Object, const unsigned char *, int);
ea1aaa6f
ST
4057{
4058 *put_func = xpm_put_color_table_v;
4059 *get_func = xpm_get_color_table_v;
4060 return Fmake_vector (make_number (256), Qnil);
4061}
4062
4063static void
4064xpm_put_color_table_v (color_table, chars_start, chars_len, color)
4065 Lisp_Object color_table;
46accb8f 4066 const unsigned char *chars_start;
ea1aaa6f
ST
4067 int chars_len;
4068 Lisp_Object color;
4069{
4070 XVECTOR (color_table)->contents[*chars_start] = color;
4071}
4072
4073static Lisp_Object
4074xpm_get_color_table_v (color_table, chars_start, chars_len)
4075 Lisp_Object color_table;
46accb8f 4076 const unsigned char *chars_start;
ea1aaa6f
ST
4077 int chars_len;
4078{
4079 return XVECTOR (color_table)->contents[*chars_start];
4080}
4081
4082static Lisp_Object
4083xpm_make_color_table_h (put_func, get_func)
46accb8f
YM
4084 void (**put_func) (Lisp_Object, const unsigned char *, int, Lisp_Object);
4085 Lisp_Object (**get_func) (Lisp_Object, const unsigned char *, int);
ea1aaa6f
ST
4086{
4087 *put_func = xpm_put_color_table_h;
4088 *get_func = xpm_get_color_table_h;
4089 return make_hash_table (Qequal, make_number (DEFAULT_HASH_SIZE),
9ecf6403
YM
4090 make_float (DEFAULT_REHASH_SIZE),
4091 make_float (DEFAULT_REHASH_THRESHOLD),
4092 Qnil, Qnil, Qnil);
ea1aaa6f
ST
4093}
4094
4095static void
4096xpm_put_color_table_h (color_table, chars_start, chars_len, color)
4097 Lisp_Object color_table;
46accb8f 4098 const unsigned char *chars_start;
ea1aaa6f
ST
4099 int chars_len;
4100 Lisp_Object color;
4101{
4102 struct Lisp_Hash_Table *table = XHASH_TABLE (color_table);
4103 unsigned hash_code;
4104 Lisp_Object chars = make_unibyte_string (chars_start, chars_len);
4105
4106 hash_lookup (table, chars, &hash_code);
4107 hash_put (table, chars, color, hash_code);
4108}
4109
4110static Lisp_Object
4111xpm_get_color_table_h (color_table, chars_start, chars_len)
4112 Lisp_Object color_table;
46accb8f 4113 const unsigned char *chars_start;
ea1aaa6f
ST
4114 int chars_len;
4115{
4116 struct Lisp_Hash_Table *table = XHASH_TABLE (color_table);
4117 int i = hash_lookup (table, make_unibyte_string (chars_start, chars_len),
9ecf6403 4118 NULL);
ea1aaa6f
ST
4119
4120 return i >= 0 ? HASH_VALUE (table, i) : Qnil;
4121}
4122
4123enum xpm_color_key {
4124 XPM_COLOR_KEY_S,
4125 XPM_COLOR_KEY_M,
4126 XPM_COLOR_KEY_G4,
4127 XPM_COLOR_KEY_G,
4128 XPM_COLOR_KEY_C
4129};
4130
46accb8f 4131static const char xpm_color_key_strings[][4] = {"s", "m", "g4", "g", "c"};
ea1aaa6f
ST
4132
4133static int
4134xpm_str_to_color_key (s)
46accb8f 4135 const char *s;
ea1aaa6f
ST
4136{
4137 int i;
4138
4139 for (i = 0;
4140 i < sizeof xpm_color_key_strings / sizeof xpm_color_key_strings[0];
4141 i++)
4142 if (strcmp (xpm_color_key_strings[i], s) == 0)
4143 return i;
4144 return -1;
4145}
4146
4147static int
4148xpm_load_image (f, img, contents, end)
4149 struct frame *f;
4150 struct image *img;
46accb8f 4151 const unsigned char *contents, *end;
ea1aaa6f 4152{
46accb8f 4153 const unsigned char *s = contents, *beg, *str;
ea1aaa6f
ST
4154 unsigned char buffer[BUFSIZ];
4155 int width, height, x, y;
4156 int num_colors, chars_per_pixel;
4157 int len, LA1;
46accb8f
YM
4158 void (*put_color_table) (Lisp_Object, const unsigned char *, int, Lisp_Object);
4159 Lisp_Object (*get_color_table) (Lisp_Object, const unsigned char *, int);
ea1aaa6f
ST
4160 Lisp_Object frame, color_symbols, color_table;
4161 int best_key, have_mask = 0;
4162 XImagePtr ximg = NULL, mask_img = NULL;
4163
4164#define match() \
4165 LA1 = xpm_scan (&s, end, &beg, &len)
4166
9ecf6403
YM
4167#define expect(TOKEN) \
4168 if (LA1 != (TOKEN)) \
4169 goto failure; \
4170 else \
ea1aaa6f
ST
4171 match ()
4172
9ecf6403 4173#define expect_ident(IDENT) \
ea1aaa6f 4174 if (LA1 == XPM_TK_IDENT \
9ecf6403
YM
4175 && strlen ((IDENT)) == len && memcmp ((IDENT), beg, len) == 0) \
4176 match (); \
4177 else \
ea1aaa6f
ST
4178 goto failure
4179
4180 if (!(end - s >= 9 && memcmp (s, "/* XPM */", 9) == 0))
4181 goto failure;
4182 s += 9;
4183 match();
4184 expect_ident ("static");
4185 expect_ident ("char");
4186 expect ('*');
4187 expect (XPM_TK_IDENT);
4188 expect ('[');
4189 expect (']');
4190 expect ('=');
4191 expect ('{');
4192 expect (XPM_TK_STRING);
4193 if (len >= BUFSIZ)
4194 goto failure;
4195 memcpy (buffer, beg, len);
4196 buffer[len] = '\0';
4197 if (sscanf (buffer, "%d %d %d %d", &width, &height,
9ecf6403 4198 &num_colors, &chars_per_pixel) != 4
ea1aaa6f
ST
4199 || width <= 0 || height <= 0
4200 || num_colors <= 0 || chars_per_pixel <= 0)
4201 goto failure;
de297941
YM
4202
4203 if (!check_image_size (f, width, height))
4204 {
4205 image_error ("Invalid image size", Qnil, Qnil);
4206 goto failure;
4207 }
4208
ea1aaa6f
ST
4209 expect (',');
4210
4211 XSETFRAME (frame, f);
4212 if (!NILP (Fxw_display_color_p (frame)))
4213 best_key = XPM_COLOR_KEY_C;
4214 else if (!NILP (Fx_display_grayscale_p (frame)))
4215 best_key = (XFASTINT (Fx_display_planes (frame)) > 2
9ecf6403 4216 ? XPM_COLOR_KEY_G : XPM_COLOR_KEY_G4);
ea1aaa6f
ST
4217 else
4218 best_key = XPM_COLOR_KEY_M;
4219
4220 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
4221 if (chars_per_pixel == 1)
4222 color_table = xpm_make_color_table_v (&put_color_table,
9ecf6403 4223 &get_color_table);
ea1aaa6f
ST
4224 else
4225 color_table = xpm_make_color_table_h (&put_color_table,
9ecf6403 4226 &get_color_table);
ea1aaa6f
ST
4227
4228 while (num_colors-- > 0)
4229 {
4230 unsigned char *color, *max_color;
4231 int key, next_key, max_key = 0;
4232 Lisp_Object symbol_color = Qnil, color_val;
4233 XColor cdef;
4234
4235 expect (XPM_TK_STRING);
4236 if (len <= chars_per_pixel || len >= BUFSIZ + chars_per_pixel)
9ecf6403 4237 goto failure;
ea1aaa6f
ST
4238 memcpy (buffer, beg + chars_per_pixel, len - chars_per_pixel);
4239 buffer[len - chars_per_pixel] = '\0';
4240
4241 str = strtok (buffer, " \t");
4242 if (str == NULL)
9ecf6403 4243 goto failure;
ea1aaa6f
ST
4244 key = xpm_str_to_color_key (str);
4245 if (key < 0)
9ecf6403 4246 goto failure;
ea1aaa6f 4247 do
9ecf6403
YM
4248 {
4249 color = strtok (NULL, " \t");
4250 if (color == NULL)
4251 goto failure;
ea1aaa6f 4252
9db94f82 4253 while ((str = strtok (NULL, " \t")) != NULL)
9ecf6403
YM
4254 {
4255 next_key = xpm_str_to_color_key (str);
4256 if (next_key >= 0)
4257 break;
4258 color[strlen (color)] = ' ';
4259 }
ea1aaa6f 4260
9ecf6403
YM
4261 if (key == XPM_COLOR_KEY_S)
4262 {
4263 if (NILP (symbol_color))
4264 symbol_color = build_string (color);
4265 }
4266 else if (max_key < key && key <= best_key)
4267 {
4268 max_key = key;
4269 max_color = color;
4270 }
4271 key = next_key;
4272 }
ea1aaa6f
ST
4273 while (str);
4274
4275 color_val = Qnil;
4276 if (!NILP (color_symbols) && !NILP (symbol_color))
9ecf6403
YM
4277 {
4278 Lisp_Object specified_color = Fassoc (symbol_color, color_symbols);
4279
4280 if (CONSP (specified_color) && STRINGP (XCDR (specified_color)))
9db94f82 4281 {
05131107 4282 if (xstrcasecmp (SDATA (XCDR (specified_color)), "None") == 0)
9db94f82
YM
4283 color_val = Qt;
4284 else if (x_defined_color (f, SDATA (XCDR (specified_color)),
4285 &cdef, 0))
4286 color_val = make_number (cdef.pixel);
4287 }
9ecf6403 4288 }
ea1aaa6f 4289 if (NILP (color_val) && max_key > 0)
9db94f82 4290 {
05131107 4291 if (xstrcasecmp (max_color, "None") == 0)
9db94f82
YM
4292 color_val = Qt;
4293 else if (x_defined_color (f, max_color, &cdef, 0))
4294 color_val = make_number (cdef.pixel);
4295 }
ea1aaa6f 4296 if (!NILP (color_val))
9ecf6403 4297 (*put_color_table) (color_table, beg, chars_per_pixel, color_val);
ea1aaa6f
ST
4298
4299 expect (',');
4300 }
4301
4302 if (!x_create_x_image_and_pixmap (f, width, height, 0,
9ecf6403 4303 &ximg, &img->pixmap)
edfda783 4304#ifndef HAVE_NS
ea1aaa6f 4305 || !x_create_x_image_and_pixmap (f, width, height, 1,
edfda783
AR
4306 &mask_img, &img->mask)
4307#endif
4308 )
ea1aaa6f
ST
4309 {
4310 image_error ("Out of memory (%s)", img->spec, Qnil);
4311 goto error;
4312 }
4313
4314 for (y = 0; y < height; y++)
4315 {
4316 expect (XPM_TK_STRING);
4317 str = beg;
4318 if (len < width * chars_per_pixel)
9ecf6403 4319 goto failure;
ea1aaa6f 4320 for (x = 0; x < width; x++, str += chars_per_pixel)
9ecf6403
YM
4321 {
4322 Lisp_Object color_val =
4323 (*get_color_table) (color_table, str, chars_per_pixel);
4324
4325 XPutPixel (ximg, x, y,
4326 (INTEGERP (color_val) ? XINT (color_val)
4327 : FRAME_FOREGROUND_PIXEL (f)));
edfda783 4328#ifndef HAVE_NS
9ecf6403
YM
4329 XPutPixel (mask_img, x, y,
4330 (!EQ (color_val, Qt) ? PIX_MASK_DRAW
4331 : (have_mask = 1, PIX_MASK_RETAIN)));
edfda783
AR
4332#else
4333 if (EQ(color_val, Qt))
4334 ns_set_alpha(ximg, x, y, 0);
4335#endif
9ecf6403 4336 }
ea1aaa6f 4337 if (y + 1 < height)
9ecf6403 4338 expect (',');
ea1aaa6f
ST
4339 }
4340
4341 img->width = width;
4342 img->height = height;
4343
0b8ac842
YM
4344 /* Maybe fill in the background field while we have ximg handy. */
4345 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
4346 IMAGE_BACKGROUND (img, f, ximg);
4347
ea1aaa6f
ST
4348 x_put_x_image (f, ximg, img->pixmap, width, height);
4349 x_destroy_x_image (ximg);
edfda783 4350#ifndef HAVE_NS
ea1aaa6f
ST
4351 if (have_mask)
4352 {
9ecf6403
YM
4353 /* Fill in the background_transparent field while we have the
4354 mask handy. */
4355 image_background_transparent (img, f, mask_img);
4356
ea1aaa6f
ST
4357 x_put_x_image (f, mask_img, img->mask, width, height);
4358 x_destroy_x_image (mask_img);
4359 }
4360 else
4361 {
4362 x_destroy_x_image (mask_img);
4363 Free_Pixmap (FRAME_X_DISPLAY (f), img->mask);
4364 img->mask = NO_PIXMAP;
4365 }
edfda783 4366#endif
ea1aaa6f
ST
4367 return 1;
4368
4369 failure:
4370 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
4371 error:
4372 x_destroy_x_image (ximg);
4373 x_destroy_x_image (mask_img);
4374 x_clear_image (f, img);
4375 return 0;
4376
4377#undef match
4378#undef expect
4379#undef expect_ident
4380}
4381
4382static int
4383xpm_load (f, img)
4384 struct frame *f;
4385 struct image *img;
4386{
4387 int success_p = 0;
4388 Lisp_Object file_name;
4389
4390 /* If IMG->spec specifies a file name, create a non-file spec from it. */
4391 file_name = image_spec_value (img->spec, QCfile, NULL);
4392 if (STRINGP (file_name))
4393 {
4394 Lisp_Object file;
4395 unsigned char *contents;
4396 int size;
4397 struct gcpro gcpro1;
4398
4399 file = x_find_image_file (file_name);
4400 GCPRO1 (file);
4401 if (!STRINGP (file))
9ecf6403
YM
4402 {
4403 image_error ("Cannot find image file `%s'", file_name, Qnil);
4404 UNGCPRO;
4405 return 0;
4406 }
ea1aaa6f
ST
4407
4408 contents = slurp_file (SDATA (file), &size);
4409 if (contents == NULL)
9ecf6403
YM
4410 {
4411 image_error ("Error loading XPM image `%s'", img->spec, Qnil);
4412 UNGCPRO;
4413 return 0;
4414 }
ea1aaa6f
ST
4415
4416 success_p = xpm_load_image (f, img, contents, contents + size);
4417 xfree (contents);
4418 UNGCPRO;
4419 }
4420 else
4421 {
4422 Lisp_Object data;
4423
4424 data = image_spec_value (img->spec, QCdata, NULL);
4425 success_p = xpm_load_image (f, img, SDATA (data),
9ecf6403 4426 SDATA (data) + SBYTES (data));
ea1aaa6f
ST
4427 }
4428
4429 return success_p;
4430}
4431
9e2a2647 4432#endif /* HAVE_NS && !HAVE_XPM */
b0da69a7 4433
ea1aaa6f 4434
4ef0d4d0
KS
4435\f
4436/***********************************************************************
4437 Color table
4438 ***********************************************************************/
4439
4440#ifdef COLOR_TABLE_SUPPORT
4441
4442/* An entry in the color table mapping an RGB color to a pixel color. */
4443
4444struct ct_color
4445{
4446 int r, g, b;
4447 unsigned long pixel;
4448
4449 /* Next in color table collision list. */
4450 struct ct_color *next;
4451};
4452
4453/* The bucket vector size to use. Must be prime. */
4454
4455#define CT_SIZE 101
4456
4457/* Value is a hash of the RGB color given by R, G, and B. */
4458
4459#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
4460
4461/* The color hash table. */
4462
4463struct ct_color **ct_table;
4464
4465/* Number of entries in the color table. */
4466
4467int ct_colors_allocated;
4468
4469/* Initialize the color table. */
4470
4471static void
4472init_color_table ()
4473{
4474 int size = CT_SIZE * sizeof (*ct_table);
4475 ct_table = (struct ct_color **) xmalloc (size);
4476 bzero (ct_table, size);
4477 ct_colors_allocated = 0;
4478}
4479
4480
4481/* Free memory associated with the color table. */
4482
4483static void
4484free_color_table ()
4485{
4486 int i;
4487 struct ct_color *p, *next;
4488
4489 for (i = 0; i < CT_SIZE; ++i)
4490 for (p = ct_table[i]; p; p = next)
4491 {
4492 next = p->next;
4493 xfree (p);
4494 }
4495
4496 xfree (ct_table);
4497 ct_table = NULL;
4498}
4499
4500
4501/* Value is a pixel color for RGB color R, G, B on frame F. If an
4502 entry for that color already is in the color table, return the
4503 pixel color of that entry. Otherwise, allocate a new color for R,
4504 G, B, and make an entry in the color table. */
4505
4506static unsigned long
4507lookup_rgb_color (f, r, g, b)
4508 struct frame *f;
4509 int r, g, b;
4510{
4511 unsigned hash = CT_HASH_RGB (r, g, b);
4512 int i = hash % CT_SIZE;
4513 struct ct_color *p;
4514 Display_Info *dpyinfo;
4515
4516 /* Handle TrueColor visuals specially, which improves performance by
4517 two orders of magnitude. Freeing colors on TrueColor visuals is
4518 a nop, and pixel colors specify RGB values directly. See also
4519 the Xlib spec, chapter 3.1. */
4520 dpyinfo = FRAME_X_DISPLAY_INFO (f);
4521 if (dpyinfo->red_bits > 0)
4522 {
4523 unsigned long pr, pg, pb;
4524
4525 /* Apply gamma-correction like normal color allocation does. */
4526 if (f->gamma)
4527 {
4528 XColor color;
4529 color.red = r, color.green = g, color.blue = b;
4530 gamma_correct (f, &color);
4531 r = color.red, g = color.green, b = color.blue;
4532 }
4533
4534 /* Scale down RGB values to the visual's bits per RGB, and shift
4535 them to the right position in the pixel color. Note that the
4536 original RGB values are 16-bit values, as usual in X. */
4537 pr = (r >> (16 - dpyinfo->red_bits)) << dpyinfo->red_offset;
4538 pg = (g >> (16 - dpyinfo->green_bits)) << dpyinfo->green_offset;
4539 pb = (b >> (16 - dpyinfo->blue_bits)) << dpyinfo->blue_offset;
4540
4541 /* Assemble the pixel color. */
4542 return pr | pg | pb;
4543 }
1f026899 4544
4ef0d4d0
KS
4545 for (p = ct_table[i]; p; p = p->next)
4546 if (p->r == r && p->g == g && p->b == b)
4547 break;
4548
4549 if (p == NULL)
4550 {
4551
4552#ifdef HAVE_X_WINDOWS
4553 XColor color;
4554 Colormap cmap;
4555 int rc;
4556
4557 color.red = r;
4558 color.green = g;
4559 color.blue = b;
4560
4561 cmap = FRAME_X_COLORMAP (f);
4562 rc = x_alloc_nearest_color (f, cmap, &color);
4563 if (rc)
4564 {
4565 ++ct_colors_allocated;
4566 p = (struct ct_color *) xmalloc (sizeof *p);
4567 p->r = r;
4568 p->g = g;
4569 p->b = b;
4570 p->pixel = color.pixel;
4571 p->next = ct_table[i];
4572 ct_table[i] = p;
4573 }
4574 else
4575 return FRAME_FOREGROUND_PIXEL (f);
4576
4577#else
4578 COLORREF color;
4579#ifdef HAVE_NTGUI
4580 color = PALETTERGB (r, g, b);
4581#else
4582 color = RGB_TO_ULONG (r, g, b);
4583#endif /* HAVE_NTGUI */
4584 ++ct_colors_allocated;
4585 p = (struct ct_color *) xmalloc (sizeof *p);
4586 p->r = r;
4587 p->g = g;
4588 p->b = b;
4589 p->pixel = color;
4590 p->next = ct_table[i];
4591 ct_table[i] = p;
4592#endif /* HAVE_X_WINDOWS */
4593
4594 }
4595
4596 return p->pixel;
4597}
4598
4599
4600/* Look up pixel color PIXEL which is used on frame F in the color
4601 table. If not already present, allocate it. Value is PIXEL. */
4602
4603static unsigned long
4604lookup_pixel_color (f, pixel)
4605 struct frame *f;
4606 unsigned long pixel;
4607{
4608 int i = pixel % CT_SIZE;
4609 struct ct_color *p;
4610
4611 for (p = ct_table[i]; p; p = p->next)
4612 if (p->pixel == pixel)
4613 break;
4614
4615 if (p == NULL)
4616 {
4617 XColor color;
4618 Colormap cmap;
4619 int rc;
4620
4621#ifdef HAVE_X_WINDOWS
4622 cmap = FRAME_X_COLORMAP (f);
4623 color.pixel = pixel;
4624 x_query_color (f, &color);
4625 rc = x_alloc_nearest_color (f, cmap, &color);
4626#else
4627 BLOCK_INPUT;
4628 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
4629 color.pixel = pixel;
4630 XQueryColor (NULL, cmap, &color);
4631 rc = x_alloc_nearest_color (f, cmap, &color);
4632 UNBLOCK_INPUT;
4633#endif /* HAVE_X_WINDOWS */
4634
4635 if (rc)
4636 {
4637 ++ct_colors_allocated;
4638
4639 p = (struct ct_color *) xmalloc (sizeof *p);
4640 p->r = color.red;
4641 p->g = color.green;
4642 p->b = color.blue;
4643 p->pixel = pixel;
4644 p->next = ct_table[i];
4645 ct_table[i] = p;
4646 }
4647 else
4648 return FRAME_FOREGROUND_PIXEL (f);
4649 }
4650 return p->pixel;
4651}
4652
4653
4654/* Value is a vector of all pixel colors contained in the color table,
4655 allocated via xmalloc. Set *N to the number of colors. */
4656
4657static unsigned long *
4658colors_in_color_table (n)
4659 int *n;
4660{
4661 int i, j;
4662 struct ct_color *p;
4663 unsigned long *colors;
4664
4665 if (ct_colors_allocated == 0)
4666 {
4667 *n = 0;
4668 colors = NULL;
4669 }
4670 else
4671 {
4672 colors = (unsigned long *) xmalloc (ct_colors_allocated
4673 * sizeof *colors);
4674 *n = ct_colors_allocated;
4675
4676 for (i = j = 0; i < CT_SIZE; ++i)
4677 for (p = ct_table[i]; p; p = p->next)
4678 colors[j++] = p->pixel;
4679 }
4680
4681 return colors;
4682}
4683
4684#else /* COLOR_TABLE_SUPPORT */
4685
4686static unsigned long
4687lookup_rgb_color (f, r, g, b)
4688 struct frame *f;
4689 int r, g, b;
4690{
4691 unsigned long pixel;
4692
4ef0d4d0
KS
4693#ifdef HAVE_NTGUI
4694 pixel = PALETTERGB (r >> 8, g >> 8, b >> 8);
4695#endif /* HAVE_NTGUI */
4696
edfda783
AR
4697#ifdef HAVE_NS
4698 pixel = RGB_TO_ULONG (r >> 8, g >> 8, b >> 8);
4699#endif /* HAVE_NS */
4ef0d4d0
KS
4700 return pixel;
4701}
4702
4703static void
4704init_color_table ()
4705{
4706}
4707#endif /* COLOR_TABLE_SUPPORT */
4708
4709\f
4710/***********************************************************************
4711 Algorithms
4712 ***********************************************************************/
4713
4714static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int));
4715static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *));
4716static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int));
4717
4718#ifdef HAVE_NTGUI
4719static void XPutPixel (XImagePtr , int, int, COLORREF);
4720#endif /* HAVE_NTGUI */
4721
4722/* Non-zero means draw a cross on images having `:conversion
4723 disabled'. */
4724
4725int cross_disabled_images;
4726
4727/* Edge detection matrices for different edge-detection
4728 strategies. */
4729
4730static int emboss_matrix[9] = {
4731 /* x - 1 x x + 1 */
4732 2, -1, 0, /* y - 1 */
4733 -1, 0, 1, /* y */
4734 0, 1, -2 /* y + 1 */
4735};
4736
4737static int laplace_matrix[9] = {
4738 /* x - 1 x x + 1 */
4739 1, 0, 0, /* y - 1 */
4740 0, 0, 0, /* y */
4741 0, 0, -1 /* y + 1 */
4742};
4743
4744/* Value is the intensity of the color whose red/green/blue values
4745 are R, G, and B. */
4746
4747#define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6)
4748
4749
4750/* On frame F, return an array of XColor structures describing image
4751 IMG->pixmap. Each XColor structure has its pixel color set. RGB_P
4752 non-zero means also fill the red/green/blue members of the XColor
4753 structures. Value is a pointer to the array of XColors structures,
4754 allocated with xmalloc; it must be freed by the caller. */
4755
4756static XColor *
4757x_to_xcolors (f, img, rgb_p)
4758 struct frame *f;
4759 struct image *img;
4760 int rgb_p;
4761{
4762 int x, y;
4763 XColor *colors, *p;
4764 XImagePtr_or_DC ximg;
4765#ifdef HAVE_NTGUI
4766 HDC hdc;
4767 HGDIOBJ prev;
4768#endif /* HAVE_NTGUI */
4769
4770 colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
4771
4772#ifndef HAVE_NTGUI
4773 /* Get the X image IMG->pixmap. */
4774 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
4775 0, 0, img->width, img->height, ~0, ZPixmap);
4776#else
4777 /* Load the image into a memory device context. */
4778 hdc = get_frame_dc (f);
4779 ximg = CreateCompatibleDC (hdc);
4780 release_frame_dc (f, hdc);
4781 prev = SelectObject (ximg, img->pixmap);
4782#endif /* HAVE_NTGUI */
4783
4784 /* Fill the `pixel' members of the XColor array. I wished there
4785 were an easy and portable way to circumvent XGetPixel. */
4786 p = colors;
4787 for (y = 0; y < img->height; ++y)
4788 {
4789 XColor *row = p;
4790
8b7d0a16 4791#if defined (HAVE_X_WINDOWS) || defined (HAVE_NTGUI)
4ef0d4d0 4792 for (x = 0; x < img->width; ++x, ++p)
8b7d0a16 4793 p->pixel = GET_PIXEL (ximg, x, y);
4ef0d4d0
KS
4794 if (rgb_p)
4795 x_query_colors (f, row, img->width);
4796
4797#else
4798
4799 for (x = 0; x < img->width; ++x, ++p)
4800 {
4801 /* W32_TODO: palette support needed here? */
4802 p->pixel = GET_PIXEL (ximg, x, y);
4803 if (rgb_p)
4804 {
4ef0d4d0
KS
4805 p->red = RED16_FROM_ULONG (p->pixel);
4806 p->green = GREEN16_FROM_ULONG (p->pixel);
4807 p->blue = BLUE16_FROM_ULONG (p->pixel);
4ef0d4d0
KS
4808 }
4809 }
4810#endif /* HAVE_X_WINDOWS */
4811 }
4812
4813 Destroy_Image (ximg, prev);
4814
4815 return colors;
4816}
4817
4818#ifdef HAVE_NTGUI
4819
4820/* Put a pixel of COLOR at position X, Y in XIMG. XIMG must have been
4821 created with CreateDIBSection, with the pointer to the bit values
4822 stored in ximg->data. */
4823
3046a84b
JB
4824static void
4825XPutPixel (ximg, x, y, color)
4ef0d4d0
KS
4826 XImagePtr ximg;
4827 int x, y;
4828 COLORREF color;
4829{
4830 int width = ximg->info.bmiHeader.biWidth;
4831 int height = ximg->info.bmiHeader.biHeight;
4832 unsigned char * pixel;
4833
4834 /* True color images. */
4835 if (ximg->info.bmiHeader.biBitCount == 24)
4836 {
4837 int rowbytes = width * 3;
4838 /* Ensure scanlines are aligned on 4 byte boundaries. */
4839 if (rowbytes % 4)
4840 rowbytes += 4 - (rowbytes % 4);
4841
4842 pixel = ximg->data + y * rowbytes + x * 3;
4843 /* Windows bitmaps are in BGR order. */
4844 *pixel = GetBValue (color);
4845 *(pixel + 1) = GetGValue (color);
4846 *(pixel + 2) = GetRValue (color);
4847 }
4848 /* Monochrome images. */
4849 else if (ximg->info.bmiHeader.biBitCount == 1)
4850 {
4851 int rowbytes = width / 8;
4852 /* Ensure scanlines are aligned on 4 byte boundaries. */
4853 if (rowbytes % 4)
4854 rowbytes += 4 - (rowbytes % 4);
4855 pixel = ximg->data + y * rowbytes + x / 8;
4856 /* Filter out palette info. */
4857 if (color & 0x00ffffff)
4858 *pixel = *pixel | (1 << x % 8);
4859 else
4860 *pixel = *pixel & ~(1 << x % 8);
4861 }
4862 else
4863 image_error ("XPutPixel: palette image not supported", Qnil, Qnil);
4864}
4865
4866#endif /* HAVE_NTGUI */
4867
4868/* Create IMG->pixmap from an array COLORS of XColor structures, whose
4869 RGB members are set. F is the frame on which this all happens.
4870 COLORS will be freed; an existing IMG->pixmap will be freed, too. */
4871
4872static void
4873x_from_xcolors (f, img, colors)
4874 struct frame *f;
4875 struct image *img;
4876 XColor *colors;
4877{
4878 int x, y;
edfda783 4879 XImagePtr oimg = NULL;
9d7112ed 4880 Pixmap pixmap;
4ef0d4d0
KS
4881 XColor *p;
4882
4883 init_color_table ();
4884
4885 x_create_x_image_and_pixmap (f, img->width, img->height, 0,
4886 &oimg, &pixmap);
4887 p = colors;
4888 for (y = 0; y < img->height; ++y)
4889 for (x = 0; x < img->width; ++x, ++p)
4890 {
4891 unsigned long pixel;
4892 pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
4893 XPutPixel (oimg, x, y, pixel);
4894 }
4895
4896 xfree (colors);
4897 x_clear_image_1 (f, img, 1, 0, 1);
4898
4899 x_put_x_image (f, oimg, pixmap, img->width, img->height);
4900 x_destroy_x_image (oimg);
4901 img->pixmap = pixmap;
4902#ifdef COLOR_TABLE_SUPPORT
4903 img->colors = colors_in_color_table (&img->ncolors);
4904 free_color_table ();
4905#endif /* COLOR_TABLE_SUPPORT */
4906}
4907
4908
4909/* On frame F, perform edge-detection on image IMG.
4910
4911 MATRIX is a nine-element array specifying the transformation
4912 matrix. See emboss_matrix for an example.
4913
4914 COLOR_ADJUST is a color adjustment added to each pixel of the
4915 outgoing image. */
4916
4917static void
4918x_detect_edges (f, img, matrix, color_adjust)
4919 struct frame *f;
4920 struct image *img;
4921 int matrix[9], color_adjust;
4922{
4923 XColor *colors = x_to_xcolors (f, img, 1);
4924 XColor *new, *p;
4925 int x, y, i, sum;
4926
4927 for (i = sum = 0; i < 9; ++i)
1ea40aa2 4928 sum += eabs (matrix[i]);
4ef0d4d0
KS
4929
4930#define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))
4931
4932 new = (XColor *) xmalloc (img->width * img->height * sizeof *new);
4933
4934 for (y = 0; y < img->height; ++y)
4935 {
4936 p = COLOR (new, 0, y);
4937 p->red = p->green = p->blue = 0xffff/2;
4938 p = COLOR (new, img->width - 1, y);
4939 p->red = p->green = p->blue = 0xffff/2;
4940 }
4941
4942 for (x = 1; x < img->width - 1; ++x)
4943 {
4944 p = COLOR (new, x, 0);
4945 p->red = p->green = p->blue = 0xffff/2;
4946 p = COLOR (new, x, img->height - 1);
4947 p->red = p->green = p->blue = 0xffff/2;
4948 }
4949
4950 for (y = 1; y < img->height - 1; ++y)
4951 {
4952 p = COLOR (new, 1, y);
4953
4954 for (x = 1; x < img->width - 1; ++x, ++p)
4955 {
4956 int r, g, b, y1, x1;
4957
4958 r = g = b = i = 0;
4959 for (y1 = y - 1; y1 < y + 2; ++y1)
4960 for (x1 = x - 1; x1 < x + 2; ++x1, ++i)
4961 if (matrix[i])
4962 {
4963 XColor *t = COLOR (colors, x1, y1);
4964 r += matrix[i] * t->red;
4965 g += matrix[i] * t->green;
4966 b += matrix[i] * t->blue;
4967 }
4968
4969 r = (r / sum + color_adjust) & 0xffff;
4970 g = (g / sum + color_adjust) & 0xffff;
4971 b = (b / sum + color_adjust) & 0xffff;
4972 p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b);
4973 }
4974 }
4975
4976 xfree (colors);
4977 x_from_xcolors (f, img, new);
4978
4979#undef COLOR
4980}
4981
4982
4983/* Perform the pre-defined `emboss' edge-detection on image IMG
4984 on frame F. */
4985
4986static void
4987x_emboss (f, img)
4988 struct frame *f;
4989 struct image *img;
4990{
4991 x_detect_edges (f, img, emboss_matrix, 0xffff / 2);
4992}
4993
4994
4995/* Transform image IMG which is used on frame F with a Laplace
4996 edge-detection algorithm. The result is an image that can be used
4997 to draw disabled buttons, for example. */
4998
4999static void
5000x_laplace (f, img)
5001 struct frame *f;
5002 struct image *img;
5003{
5004 x_detect_edges (f, img, laplace_matrix, 45000);
5005}
5006
5007
5008/* Perform edge-detection on image IMG on frame F, with specified
5009 transformation matrix MATRIX and color-adjustment COLOR_ADJUST.
5010
5011 MATRIX must be either
5012
5013 - a list of at least 9 numbers in row-major form
5014 - a vector of at least 9 numbers
5015
5016 COLOR_ADJUST nil means use a default; otherwise it must be a
5017 number. */
5018
5019static void
5020x_edge_detection (f, img, matrix, color_adjust)
5021 struct frame *f;
5022 struct image *img;
5023 Lisp_Object matrix, color_adjust;
5024{
5025 int i = 0;
5026 int trans[9];
5027
5028 if (CONSP (matrix))
5029 {
5030 for (i = 0;
5031 i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix));
5032 ++i, matrix = XCDR (matrix))
5033 trans[i] = XFLOATINT (XCAR (matrix));
5034 }
5035 else if (VECTORP (matrix) && ASIZE (matrix) >= 9)
5036 {
5037 for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i)
5038 trans[i] = XFLOATINT (AREF (matrix, i));
5039 }
5040
5041 if (NILP (color_adjust))
5042 color_adjust = make_number (0xffff / 2);
5043
5044 if (i == 9 && NUMBERP (color_adjust))
5045 x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust));
5046}
5047
5048
5049/* Transform image IMG on frame F so that it looks disabled. */
5050
5051static void
5052x_disable_image (f, img)
5053 struct frame *f;
5054 struct image *img;
5055{
5056 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
5057#ifdef HAVE_NTGUI
5058 int n_planes = dpyinfo->n_planes * dpyinfo->n_cbits;
5059#else
5060 int n_planes = dpyinfo->n_planes;
5061#endif /* HAVE_NTGUI */
5062
5063 if (n_planes >= 2)
5064 {
5065 /* Color (or grayscale). Convert to gray, and equalize. Just
5066 drawing such images with a stipple can look very odd, so
5067 we're using this method instead. */
5068 XColor *colors = x_to_xcolors (f, img, 1);
5069 XColor *p, *end;
5070 const int h = 15000;
5071 const int l = 30000;
5072
5073 for (p = colors, end = colors + img->width * img->height;
5074 p < end;
5075 ++p)
5076 {
5077 int i = COLOR_INTENSITY (p->red, p->green, p->blue);
5078 int i2 = (0xffff - h - l) * i / 0xffff + l;
5079 p->red = p->green = p->blue = i2;
5080 }
5081
5082 x_from_xcolors (f, img, colors);
5083 }
5084
5085 /* Draw a cross over the disabled image, if we must or if we
5086 should. */
5087 if (n_planes < 2 || cross_disabled_images)
5088 {
5089#ifndef HAVE_NTGUI
5090 Display *dpy = FRAME_X_DISPLAY (f);
5091 GC gc;
5092
edfda783
AR
5093#ifndef HAVE_NS //TODO: NS support, however this not needed for toolbars
5094
4ef0d4d0 5095#define MaskForeground(f) WHITE_PIX_DEFAULT (f)
4ef0d4d0 5096
ae8279db 5097 gc = XCreateGC (dpy, img->pixmap, 0, NULL);
4ef0d4d0
KS
5098 XSetForeground (dpy, gc, BLACK_PIX_DEFAULT (f));
5099 XDrawLine (dpy, img->pixmap, gc, 0, 0,
5100 img->width - 1, img->height - 1);
5101 XDrawLine (dpy, img->pixmap, gc, 0, img->height - 1,
5102 img->width - 1, 0);
5103 XFreeGC (dpy, gc);
5104
5105 if (img->mask)
5106 {
ae8279db 5107 gc = XCreateGC (dpy, img->mask, 0, NULL);
4ef0d4d0
KS
5108 XSetForeground (dpy, gc, MaskForeground (f));
5109 XDrawLine (dpy, img->mask, gc, 0, 0,
5110 img->width - 1, img->height - 1);
5111 XDrawLine (dpy, img->mask, gc, 0, img->height - 1,
5112 img->width - 1, 0);
5113 XFreeGC (dpy, gc);
5114 }
edfda783 5115#endif /* !HAVE_NS */
4ef0d4d0
KS
5116#else
5117 HDC hdc, bmpdc;
5118 HGDIOBJ prev;
5119
5120 hdc = get_frame_dc (f);
5121 bmpdc = CreateCompatibleDC (hdc);
5122 release_frame_dc (f, hdc);
5123
5124 prev = SelectObject (bmpdc, img->pixmap);
5125
5126 SetTextColor (bmpdc, BLACK_PIX_DEFAULT (f));
5127 MoveToEx (bmpdc, 0, 0, NULL);
5128 LineTo (bmpdc, img->width - 1, img->height - 1);
5129 MoveToEx (bmpdc, 0, img->height - 1, NULL);
5130 LineTo (bmpdc, img->width - 1, 0);
5131
5132 if (img->mask)
5133 {
5134 SelectObject (bmpdc, img->mask);
5135 SetTextColor (bmpdc, WHITE_PIX_DEFAULT (f));
5136 MoveToEx (bmpdc, 0, 0, NULL);
5137 LineTo (bmpdc, img->width - 1, img->height - 1);
5138 MoveToEx (bmpdc, 0, img->height - 1, NULL);
5139 LineTo (bmpdc, img->width - 1, 0);
5140 }
5141 SelectObject (bmpdc, prev);
5142 DeleteDC (bmpdc);
5143#endif /* HAVE_NTGUI */
5144 }
5145}
5146
5147
5148/* Build a mask for image IMG which is used on frame F. FILE is the
5149 name of an image file, for error messages. HOW determines how to
5150 determine the background color of IMG. If it is a list '(R G B)',
5151 with R, G, and B being integers >= 0, take that as the color of the
5152 background. Otherwise, determine the background color of IMG
5153 heuristically. Value is non-zero if successful. */
5154
5155static int
5156x_build_heuristic_mask (f, img, how)
5157 struct frame *f;
5158 struct image *img;
5159 Lisp_Object how;
5160{
5161 XImagePtr_or_DC ximg;
5162#ifndef HAVE_NTGUI
5163 XImagePtr mask_img;
5164#else
5165 HDC frame_dc;
5166 HGDIOBJ prev;
5167 char *mask_img;
5168 int row_width;
5169#endif /* HAVE_NTGUI */
5170 int x, y, rc, use_img_background;
5171 unsigned long bg = 0;
5172
5173 if (img->mask)
5174 {
5175 Free_Pixmap (FRAME_X_DISPLAY (f), img->mask);
5176 img->mask = NO_PIXMAP;
5177 img->background_transparent_valid = 0;
5178 }
5179
5180#ifndef HAVE_NTGUI
edfda783 5181#ifndef HAVE_NS
4ef0d4d0
KS
5182 /* Create an image and pixmap serving as mask. */
5183 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
5184 &mask_img, &img->mask);
5185 if (!rc)
5186 return 0;
edfda783 5187#endif /* !HAVE_NS */
4ef0d4d0
KS
5188
5189 /* Get the X image of IMG->pixmap. */
5190 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap, 0, 0,
5191 img->width, img->height,
5192 ~0, ZPixmap);
5193#else
5194 /* Create the bit array serving as mask. */
5195 row_width = (img->width + 7) / 8;
5196 mask_img = xmalloc (row_width * img->height);
5197 bzero (mask_img, row_width * img->height);
5198
5199 /* Create a memory device context for IMG->pixmap. */
5200 frame_dc = get_frame_dc (f);
5201 ximg = CreateCompatibleDC (frame_dc);
5202 release_frame_dc (f, frame_dc);
5203 prev = SelectObject (ximg, img->pixmap);
5204#endif /* HAVE_NTGUI */
5205
5206 /* Determine the background color of ximg. If HOW is `(R G B)'
5207 take that as color. Otherwise, use the image's background color. */
5208 use_img_background = 1;
5209
5210 if (CONSP (how))
5211 {
5212 int rgb[3], i;
5213
5214 for (i = 0; i < 3 && CONSP (how) && NATNUMP (XCAR (how)); ++i)
5215 {
5216 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
5217 how = XCDR (how);
5218 }
5219
5220 if (i == 3 && NILP (how))
5221 {
5222 char color_name[30];
5223 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
5224 bg = (
5225#ifdef HAVE_NTGUI
5226 0x00ffffff & /* Filter out palette info. */
5227#endif /* HAVE_NTGUI */
5228 x_alloc_image_color (f, img, build_string (color_name), 0));
5229 use_img_background = 0;
5230 }
5231 }
5232
5233 if (use_img_background)
6ac3c7bb 5234 bg = four_corners_best (ximg, img->corners, img->width, img->height);
4ef0d4d0
KS
5235
5236 /* Set all bits in mask_img to 1 whose color in ximg is different
5237 from the background color bg. */
5238#ifndef HAVE_NTGUI
5239 for (y = 0; y < img->height; ++y)
5240 for (x = 0; x < img->width; ++x)
edfda783 5241#ifndef HAVE_NS
4ef0d4d0 5242 XPutPixel (mask_img, x, y, (XGetPixel (ximg, x, y) != bg
9ecf6403 5243 ? PIX_MASK_DRAW : PIX_MASK_RETAIN));
edfda783
AR
5244#else
5245 if (XGetPixel (ximg, x, y) == bg)
5246 ns_set_alpha(ximg, x, y, 0);
5247#endif /* HAVE_NS */
5248#ifndef HAVE_NS
4ef0d4d0
KS
5249 /* Fill in the background_transparent field while we have the mask handy. */
5250 image_background_transparent (img, f, mask_img);
5251
5252 /* Put mask_img into img->mask. */
5253 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
5254 x_destroy_x_image (mask_img);
edfda783 5255#endif /* !HAVE_NS */
4ef0d4d0
KS
5256#else
5257 for (y = 0; y < img->height; ++y)
5258 for (x = 0; x < img->width; ++x)
5259 {
5260 COLORREF p = GetPixel (ximg, x, y);
5261 if (p != bg)
5262 mask_img[y * row_width + x / 8] |= 1 << (x % 8);
5263 }
5264
5265 /* Create the mask image. */
5266 img->mask = w32_create_pixmap_from_bitmap_data (img->width, img->height,
5267 mask_img);
5268 /* Fill in the background_transparent field while we have the mask handy. */
5269 SelectObject (ximg, img->mask);
5270 image_background_transparent (img, f, ximg);
5271
5272 /* Was: x_destroy_x_image ((XImagePtr )mask_img); which seems bogus ++kfs */
5273 xfree (mask_img);
5274#endif /* HAVE_NTGUI */
5275
5276 Destroy_Image (ximg, prev);
5277
5278 return 1;
5279}
5280
5281\f
5282/***********************************************************************
5283 PBM (mono, gray, color)
5284 ***********************************************************************/
5285
5286static int pbm_image_p P_ ((Lisp_Object object));
5287static int pbm_load P_ ((struct frame *f, struct image *img));
5288static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
5289
5290/* The symbol `pbm' identifying images of this type. */
5291
5292Lisp_Object Qpbm;
5293
5294/* Indices of image specification fields in gs_format, below. */
5295
5296enum pbm_keyword_index
5297{
5298 PBM_TYPE,
5299 PBM_FILE,
5300 PBM_DATA,
5301 PBM_ASCENT,
5302 PBM_MARGIN,
5303 PBM_RELIEF,
5304 PBM_ALGORITHM,
5305 PBM_HEURISTIC_MASK,
5306 PBM_MASK,
5307 PBM_FOREGROUND,
5308 PBM_BACKGROUND,
5309 PBM_LAST
5310};
5311
5312/* Vector of image_keyword structures describing the format
5313 of valid user-defined image specifications. */
5314
5315static struct image_keyword pbm_format[PBM_LAST] =
5316{
5317 {":type", IMAGE_SYMBOL_VALUE, 1},
5318 {":file", IMAGE_STRING_VALUE, 0},
5319 {":data", IMAGE_STRING_VALUE, 0},
5320 {":ascent", IMAGE_ASCENT_VALUE, 0},
5321 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
5322 {":relief", IMAGE_INTEGER_VALUE, 0},
5323 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5324 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5325 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5326 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
5327 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
5328};
5329
5330/* Structure describing the image type `pbm'. */
5331
5332static struct image_type pbm_type =
5333{
5334 &Qpbm,
5335 pbm_image_p,
5336 pbm_load,
5337 x_clear_image,
5338 NULL
5339};
5340
5341
5342/* Return non-zero if OBJECT is a valid PBM image specification. */
5343
5344static int
5345pbm_image_p (object)
5346 Lisp_Object object;
5347{
5348 struct image_keyword fmt[PBM_LAST];
5349
5350 bcopy (pbm_format, fmt, sizeof fmt);
5351
5352 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm))
5353 return 0;
5354
5355 /* Must specify either :data or :file. */
5356 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
5357}
5358
5359
5360/* Scan a decimal number from *S and return it. Advance *S while
5361 reading the number. END is the end of the string. Value is -1 at
5362 end of input. */
5363
5364static int
5365pbm_scan_number (s, end)
5366 unsigned char **s, *end;
5367{
5368 int c = 0, val = -1;
5369
5370 while (*s < end)
5371 {
5372 /* Skip white-space. */
5373 while (*s < end && (c = *(*s)++, isspace (c)))
5374 ;
5375
5376 if (c == '#')
5377 {
5378 /* Skip comment to end of line. */
5379 while (*s < end && (c = *(*s)++, c != '\n'))
5380 ;
5381 }
5382 else if (isdigit (c))
5383 {
5384 /* Read decimal number. */
5385 val = c - '0';
5386 while (*s < end && (c = *(*s)++, isdigit (c)))
5387 val = 10 * val + c - '0';
5388 break;
5389 }
5390 else
5391 break;
5392 }
5393
5394 return val;
5395}
5396
5397
5398#ifdef HAVE_NTGUI
5399#if 0 /* Unused. ++kfs */
5400
5401/* Read FILE into memory. Value is a pointer to a buffer allocated
5402 with xmalloc holding FILE's contents. Value is null if an error
5403 occurred. *SIZE is set to the size of the file. */
5404
5405static char *
5406pbm_read_file (file, size)
5407 Lisp_Object file;
5408 int *size;
5409{
5410 FILE *fp = NULL;
5411 char *buf = NULL;
5412 struct stat st;
5413
5414 if (stat (SDATA (file), &st) == 0
5415 && (fp = fopen (SDATA (file), "rb")) != NULL
5416 && (buf = (char *) xmalloc (st.st_size),
5417 fread (buf, 1, st.st_size, fp) == st.st_size))
5418 {
5419 *size = st.st_size;
5420 fclose (fp);
5421 }
5422 else
5423 {
5424 if (fp)
5425 fclose (fp);
5426 if (buf)
5427 {
5428 xfree (buf);
5429 buf = NULL;
5430 }
5431 }
5432
5433 return buf;
5434}
5435#endif
5436#endif /* HAVE_NTGUI */
5437
5438/* Load PBM image IMG for use on frame F. */
5439
5440static int
5441pbm_load (f, img)
5442 struct frame *f;
5443 struct image *img;
5444{
5445 int raw_p, x, y;
5446 int width, height, max_color_idx = 0;
5447 XImagePtr ximg;
5448 Lisp_Object file, specified_file;
5449 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
5450 struct gcpro gcpro1;
5451 unsigned char *contents = NULL;
5452 unsigned char *end, *p;
5453 int size;
5454
5455 specified_file = image_spec_value (img->spec, QCfile, NULL);
5456 file = Qnil;
5457 GCPRO1 (file);
5458
5459 if (STRINGP (specified_file))
5460 {
5461 file = x_find_image_file (specified_file);
5462 if (!STRINGP (file))
5463 {
5464 image_error ("Cannot find image file `%s'", specified_file, Qnil);
5465 UNGCPRO;
5466 return 0;
5467 }
5468
5469 contents = slurp_file (SDATA (file), &size);
5470 if (contents == NULL)
5471 {
5472 image_error ("Error reading `%s'", file, Qnil);
5473 UNGCPRO;
5474 return 0;
5475 }
5476
5477 p = contents;
5478 end = contents + size;
5479 }
5480 else
5481 {
5482 Lisp_Object data;
5483 data = image_spec_value (img->spec, QCdata, NULL);
5484 p = SDATA (data);
5485 end = p + SBYTES (data);
5486 }
5487
5488 /* Check magic number. */
5489 if (end - p < 2 || *p++ != 'P')
5490 {
5491 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
5492 error:
5493 xfree (contents);
5494 UNGCPRO;
5495 return 0;
5496 }
5497
5498 switch (*p++)
5499 {
5500 case '1':
5501 raw_p = 0, type = PBM_MONO;
5502 break;
5503
5504 case '2':
5505 raw_p = 0, type = PBM_GRAY;
5506 break;
5507
5508 case '3':
5509 raw_p = 0, type = PBM_COLOR;
5510 break;
5511
5512 case '4':
5513 raw_p = 1, type = PBM_MONO;
5514 break;
5515
5516 case '5':
5517 raw_p = 1, type = PBM_GRAY;
5518 break;
5519
5520 case '6':
5521 raw_p = 1, type = PBM_COLOR;
5522 break;
5523
5524 default:
5525 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
5526 goto error;
5527 }
5528
5529 /* Read width, height, maximum color-component. Characters
5530 starting with `#' up to the end of a line are ignored. */
5531 width = pbm_scan_number (&p, end);
5532 height = pbm_scan_number (&p, end);
5533
5534 if (type != PBM_MONO)
5535 {
5536 max_color_idx = pbm_scan_number (&p, end);
b9c89e11
JR
5537 if (max_color_idx > 65535 || max_color_idx < 0)
5538 {
5539 image_error ("Unsupported maximum PBM color value", Qnil, Qnil);
5540 goto error;
5541 }
4ef0d4d0
KS
5542 }
5543
b9c89e11
JR
5544 if (!check_image_size (f, width, height))
5545 {
5546 image_error ("Invalid image size", Qnil, Qnil);
5547 goto error;
5548 }
4ef0d4d0
KS
5549
5550 if (!x_create_x_image_and_pixmap (f, width, height, 0,
5551 &ximg, &img->pixmap))
5552 goto error;
5553
5554 /* Initialize the color hash table. */
5555 init_color_table ();
5556
5557 if (type == PBM_MONO)
5558 {
5559 int c = 0, g;
5560 struct image_keyword fmt[PBM_LAST];
5561 unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
5562 unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
5563
5564 /* Parse the image specification. */
5565 bcopy (pbm_format, fmt, sizeof fmt);
5566 parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
5567
5568 /* Get foreground and background colors, maybe allocate colors. */
5569 if (fmt[PBM_FOREGROUND].count
5570 && STRINGP (fmt[PBM_FOREGROUND].value))
5571 fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
5572 if (fmt[PBM_BACKGROUND].count
5573 && STRINGP (fmt[PBM_BACKGROUND].value))
5574 {
5575 bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg);
5576 img->background = bg;
5577 img->background_valid = 1;
5578 }
5579
5580 for (y = 0; y < height; ++y)
5581 for (x = 0; x < width; ++x)
5582 {
5583 if (raw_p)
5584 {
5585 if ((x & 7) == 0)
c295e710
CY
5586 {
5587 if (p >= end)
5588 {
5589 x_destroy_x_image (ximg);
5590 x_clear_image (f, img);
5591 image_error ("Invalid image size in image `%s'",
5592 img->spec, Qnil);
5593 goto error;
5594 }
5595 c = *p++;
5596 }
4ef0d4d0
KS
5597 g = c & 0x80;
5598 c <<= 1;
5599 }
5600 else
5601 g = pbm_scan_number (&p, end);
5602
5603 XPutPixel (ximg, x, y, g ? fg : bg);
5604 }
5605 }
5606 else
5607 {
b9c89e11
JR
5608 int expected_size = height * width;
5609 if (max_color_idx > 255)
5610 expected_size *= 2;
5611 if (type == PBM_COLOR)
5612 expected_size *= 3;
5613
5614 if (raw_p && p + expected_size > end)
39e653ea
CY
5615 {
5616 x_destroy_x_image (ximg);
fb0b0862 5617 x_clear_image (f, img);
39e653ea
CY
5618 image_error ("Invalid image size in image `%s'",
5619 img->spec, Qnil);
5620 goto error;
5621 }
5622
4ef0d4d0
KS
5623 for (y = 0; y < height; ++y)
5624 for (x = 0; x < width; ++x)
5625 {
5626 int r, g, b;
5627
b9c89e11
JR
5628 if (type == PBM_GRAY && raw_p)
5629 {
5630 r = g = b = *p++;
5631 if (max_color_idx > 255)
5632 r = g = b = r * 256 + *p++;
5633 }
5634 else if (type == PBM_GRAY)
5635 r = g = b = pbm_scan_number (&p, end);
4ef0d4d0
KS
5636 else if (raw_p)
5637 {
5638 r = *p++;
b9c89e11
JR
5639 if (max_color_idx > 255)
5640 r = r * 256 + *p++;
4ef0d4d0 5641 g = *p++;
b9c89e11
JR
5642 if (max_color_idx > 255)
5643 g = g * 256 + *p++;
4ef0d4d0 5644 b = *p++;
b9c89e11
JR
5645 if (max_color_idx > 255)
5646 b = b * 256 + *p++;
4ef0d4d0
KS
5647 }
5648 else
5649 {
5650 r = pbm_scan_number (&p, end);
5651 g = pbm_scan_number (&p, end);
5652 b = pbm_scan_number (&p, end);
5653 }
5654
5655 if (r < 0 || g < 0 || b < 0)
5656 {
5657 x_destroy_x_image (ximg);
5658 image_error ("Invalid pixel value in image `%s'",
5659 img->spec, Qnil);
5660 goto error;
5661 }
5662
5663 /* RGB values are now in the range 0..max_color_idx.
5664 Scale this to the range 0..0xffff supported by X. */
5665 r = (double) r * 65535 / max_color_idx;
5666 g = (double) g * 65535 / max_color_idx;
5667 b = (double) b * 65535 / max_color_idx;
5668 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
5669 }
5670 }
5671
5672#ifdef COLOR_TABLE_SUPPORT
5673 /* Store in IMG->colors the colors allocated for the image, and
5674 free the color table. */
5675 img->colors = colors_in_color_table (&img->ncolors);
5676 free_color_table ();
5677#endif /* COLOR_TABLE_SUPPORT */
5678
5679 img->width = width;
5680 img->height = height;
5681
5682 /* Maybe fill in the background field while we have ximg handy. */
5683
5684 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
2e09fef1
EZ
5685 /* Casting avoids a GCC warning. */
5686 IMAGE_BACKGROUND (img, f, (XImagePtr_or_DC)ximg);
4ef0d4d0
KS
5687
5688 /* Put the image into a pixmap. */
5689 x_put_x_image (f, ximg, img->pixmap, width, height);
5690 x_destroy_x_image (ximg);
5691
5692 /* X and W32 versions did it here, MAC version above. ++kfs
1f026899 5693 img->width = width;
4ef0d4d0
KS
5694 img->height = height; */
5695
5696 UNGCPRO;
5697 xfree (contents);
5698 return 1;
5699}
5700
5701\f
5702/***********************************************************************
5703 PNG
5704 ***********************************************************************/
5705
9e2a2647 5706#if defined (HAVE_PNG) || defined (HAVE_NS)
4ef0d4d0
KS
5707
5708/* Function prototypes. */
5709
5710static int png_image_p P_ ((Lisp_Object object));
5711static int png_load P_ ((struct frame *f, struct image *img));
5712
5713/* The symbol `png' identifying images of this type. */
5714
5715Lisp_Object Qpng;
5716
5717/* Indices of image specification fields in png_format, below. */
5718
5719enum png_keyword_index
5720{
5721 PNG_TYPE,
5722 PNG_DATA,
5723 PNG_FILE,
5724 PNG_ASCENT,
5725 PNG_MARGIN,
5726 PNG_RELIEF,
5727 PNG_ALGORITHM,
5728 PNG_HEURISTIC_MASK,
5729 PNG_MASK,
5730 PNG_BACKGROUND,
5731 PNG_LAST
5732};
5733
5734/* Vector of image_keyword structures describing the format
5735 of valid user-defined image specifications. */
5736
5737static struct image_keyword png_format[PNG_LAST] =
5738{
5739 {":type", IMAGE_SYMBOL_VALUE, 1},
5740 {":data", IMAGE_STRING_VALUE, 0},
5741 {":file", IMAGE_STRING_VALUE, 0},
5742 {":ascent", IMAGE_ASCENT_VALUE, 0},
5743 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
5744 {":relief", IMAGE_INTEGER_VALUE, 0},
5745 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5746 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5747 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5748 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
5749};
5750
5751/* Structure describing the image type `png'. */
5752
5753static struct image_type png_type =
5754{
5755 &Qpng,
5756 png_image_p,
5757 png_load,
5758 x_clear_image,
5759 NULL
5760};
5761
5762/* Return non-zero if OBJECT is a valid PNG image specification. */
5763
5764static int
5765png_image_p (object)
5766 Lisp_Object object;
5767{
5768 struct image_keyword fmt[PNG_LAST];
5769 bcopy (png_format, fmt, sizeof fmt);
5770
5771 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng))
5772 return 0;
5773
5774 /* Must specify either the :data or :file keyword. */
5775 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
5776}
5777
9e2a2647 5778#endif /* HAVE_PNG || HAVE_NS */
4ef0d4d0
KS
5779
5780
5781#ifdef HAVE_PNG
5782
5783#if defined HAVE_LIBPNG_PNG_H
5784# include <libpng/png.h>
5785#else
5786# include <png.h>
5787#endif
5788
5789#ifdef HAVE_NTGUI
5790/* PNG library details. */
5791
5792DEF_IMGLIB_FN (png_get_io_ptr);
5793DEF_IMGLIB_FN (png_check_sig);
5794DEF_IMGLIB_FN (png_create_read_struct);
5795DEF_IMGLIB_FN (png_create_info_struct);
5796DEF_IMGLIB_FN (png_destroy_read_struct);
5797DEF_IMGLIB_FN (png_set_read_fn);
4ef0d4d0
KS
5798DEF_IMGLIB_FN (png_set_sig_bytes);
5799DEF_IMGLIB_FN (png_read_info);
5800DEF_IMGLIB_FN (png_get_IHDR);
5801DEF_IMGLIB_FN (png_get_valid);
5802DEF_IMGLIB_FN (png_set_strip_16);
5803DEF_IMGLIB_FN (png_set_expand);
5804DEF_IMGLIB_FN (png_set_gray_to_rgb);
5805DEF_IMGLIB_FN (png_set_background);
5806DEF_IMGLIB_FN (png_get_bKGD);
5807DEF_IMGLIB_FN (png_read_update_info);
5808DEF_IMGLIB_FN (png_get_channels);
5809DEF_IMGLIB_FN (png_get_rowbytes);
5810DEF_IMGLIB_FN (png_read_image);
5811DEF_IMGLIB_FN (png_read_end);
5812DEF_IMGLIB_FN (png_error);
5813
5814static int
0855eb52 5815init_png_functions (Lisp_Object libraries)
4ef0d4d0
KS
5816{
5817 HMODULE library;
5818
4ef0d4d0 5819 /* Try loading libpng under probable names. */
0855eb52 5820 if (!(library = w32_delayed_load (libraries, Qpng)))
4ef0d4d0
KS
5821 return 0;
5822
5823 LOAD_IMGLIB_FN (library, png_get_io_ptr);
5824 LOAD_IMGLIB_FN (library, png_check_sig);
5825 LOAD_IMGLIB_FN (library, png_create_read_struct);
5826 LOAD_IMGLIB_FN (library, png_create_info_struct);
5827 LOAD_IMGLIB_FN (library, png_destroy_read_struct);
5828 LOAD_IMGLIB_FN (library, png_set_read_fn);
4ef0d4d0
KS
5829 LOAD_IMGLIB_FN (library, png_set_sig_bytes);
5830 LOAD_IMGLIB_FN (library, png_read_info);
5831 LOAD_IMGLIB_FN (library, png_get_IHDR);
5832 LOAD_IMGLIB_FN (library, png_get_valid);
5833 LOAD_IMGLIB_FN (library, png_set_strip_16);
5834 LOAD_IMGLIB_FN (library, png_set_expand);
5835 LOAD_IMGLIB_FN (library, png_set_gray_to_rgb);
5836 LOAD_IMGLIB_FN (library, png_set_background);
5837 LOAD_IMGLIB_FN (library, png_get_bKGD);
5838 LOAD_IMGLIB_FN (library, png_read_update_info);
5839 LOAD_IMGLIB_FN (library, png_get_channels);
5840 LOAD_IMGLIB_FN (library, png_get_rowbytes);
5841 LOAD_IMGLIB_FN (library, png_read_image);
5842 LOAD_IMGLIB_FN (library, png_read_end);
5843 LOAD_IMGLIB_FN (library, png_error);
5844 return 1;
5845}
5846#else
5847
5848#define fn_png_get_io_ptr png_get_io_ptr
5849#define fn_png_check_sig png_check_sig
5850#define fn_png_create_read_struct png_create_read_struct
5851#define fn_png_create_info_struct png_create_info_struct
5852#define fn_png_destroy_read_struct png_destroy_read_struct
5853#define fn_png_set_read_fn png_set_read_fn
4ef0d4d0
KS
5854#define fn_png_set_sig_bytes png_set_sig_bytes
5855#define fn_png_read_info png_read_info
5856#define fn_png_get_IHDR png_get_IHDR
5857#define fn_png_get_valid png_get_valid
5858#define fn_png_set_strip_16 png_set_strip_16
5859#define fn_png_set_expand png_set_expand
5860#define fn_png_set_gray_to_rgb png_set_gray_to_rgb
5861#define fn_png_set_background png_set_background
5862#define fn_png_get_bKGD png_get_bKGD
5863#define fn_png_read_update_info png_read_update_info
5864#define fn_png_get_channels png_get_channels
5865#define fn_png_get_rowbytes png_get_rowbytes
5866#define fn_png_read_image png_read_image
5867#define fn_png_read_end png_read_end
5868#define fn_png_error png_error
5869
5870#endif /* HAVE_NTGUI */
5871
5872/* Error and warning handlers installed when the PNG library
5873 is initialized. */
5874
5875static void
5876my_png_error (png_ptr, msg)
5877 png_struct *png_ptr;
5878 char *msg;
5879{
5880 xassert (png_ptr != NULL);
5881 image_error ("PNG error: %s", build_string (msg), Qnil);
5882 longjmp (png_ptr->jmpbuf, 1);
5883}
5884
5885
5886static void
5887my_png_warning (png_ptr, msg)
5888 png_struct *png_ptr;
5889 char *msg;
5890{
5891 xassert (png_ptr != NULL);
5892 image_error ("PNG warning: %s", build_string (msg), Qnil);
5893}
5894
5895/* Memory source for PNG decoding. */
5896
5897struct png_memory_storage
5898{
5899 unsigned char *bytes; /* The data */
5900 size_t len; /* How big is it? */
5901 int index; /* Where are we? */
5902};
5903
5904
5905/* Function set as reader function when reading PNG image from memory.
5906 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
5907 bytes from the input to DATA. */
5908
5909static void
5910png_read_from_memory (png_ptr, data, length)
5911 png_structp png_ptr;
5912 png_bytep data;
5913 png_size_t length;
5914{
5915 struct png_memory_storage *tbr
5916 = (struct png_memory_storage *) fn_png_get_io_ptr (png_ptr);
5917
5918 if (length > tbr->len - tbr->index)
5919 fn_png_error (png_ptr, "Read error");
5920
5921 bcopy (tbr->bytes + tbr->index, data, length);
5922 tbr->index = tbr->index + length;
5923}
5924
b0da69a7 5925
9a22a004
JB
5926/* Function set as reader function when reading PNG image from a file.
5927 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
5928 bytes from the input to DATA. */
5929
5930static void
5931png_read_from_file (png_ptr, data, length)
5932 png_structp png_ptr;
5933 png_bytep data;
5934 png_size_t length;
5935{
5936 FILE *fp = (FILE *) fn_png_get_io_ptr (png_ptr);
5937
5938 if (fread (data, 1, length, fp) < length)
5939 fn_png_error (png_ptr, "Read error");
5940}
5941
5942
4ef0d4d0
KS
5943/* Load PNG image IMG for use on frame F. Value is non-zero if
5944 successful. */
5945
5946static int
5947png_load (f, img)
5948 struct frame *f;
5949 struct image *img;
5950{
5951 Lisp_Object file, specified_file;
5952 Lisp_Object specified_data;
5953 int x, y, i;
5954 XImagePtr ximg, mask_img = NULL;
5955 struct gcpro gcpro1;
5956 png_struct *png_ptr = NULL;
5957 png_info *info_ptr = NULL, *end_info = NULL;
5958 FILE *volatile fp = NULL;
5959 png_byte sig[8];
5960 png_byte * volatile pixels = NULL;
5961 png_byte ** volatile rows = NULL;
5962 png_uint_32 width, height;
5963 int bit_depth, color_type, interlace_type;
5964 png_byte channels;
5965 png_uint_32 row_bytes;
5966 int transparent_p;
4ef0d4d0
KS
5967 struct png_memory_storage tbr; /* Data to be read */
5968
5969 /* Find out what file to load. */
5970 specified_file = image_spec_value (img->spec, QCfile, NULL);
5971 specified_data = image_spec_value (img->spec, QCdata, NULL);
5972 file = Qnil;
5973 GCPRO1 (file);
5974
5975 if (NILP (specified_data))
5976 {
5977 file = x_find_image_file (specified_file);
5978 if (!STRINGP (file))
5979 {
5980 image_error ("Cannot find image file `%s'", specified_file, Qnil);
5981 UNGCPRO;
5982 return 0;
5983 }
5984
5985 /* Open the image file. */
5986 fp = fopen (SDATA (file), "rb");
5987 if (!fp)
5988 {
5989 image_error ("Cannot open image file `%s'", file, Qnil);
5990 UNGCPRO;
4ef0d4d0
KS
5991 return 0;
5992 }
5993
5994 /* Check PNG signature. */
5995 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
5996 || !fn_png_check_sig (sig, sizeof sig))
5997 {
5998 image_error ("Not a PNG file: `%s'", file, Qnil);
5999 UNGCPRO;
6000 fclose (fp);
6001 return 0;
6002 }
6003 }
6004 else
6005 {
6006 /* Read from memory. */
6007 tbr.bytes = SDATA (specified_data);
6008 tbr.len = SBYTES (specified_data);
6009 tbr.index = 0;
6010
6011 /* Check PNG signature. */
6012 if (tbr.len < sizeof sig
6013 || !fn_png_check_sig (tbr.bytes, sizeof sig))
6014 {
6015 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
6016 UNGCPRO;
6017 return 0;
6018 }
6019
6020 /* Need to skip past the signature. */
6021 tbr.bytes += sizeof (sig);
6022 }
6023
2e09fef1
EZ
6024 /* Initialize read and info structs for PNG lib. Casting return
6025 value avoids a GCC warning on W32. */
6026 png_ptr = (png_structp)fn_png_create_read_struct (PNG_LIBPNG_VER_STRING,
6027 NULL, my_png_error,
6028 my_png_warning);
4ef0d4d0
KS
6029 if (!png_ptr)
6030 {
6031 if (fp) fclose (fp);
6032 UNGCPRO;
6033 return 0;
6034 }
6035
2e09fef1
EZ
6036 /* Casting return value avoids a GCC warning on W32. */
6037 info_ptr = (png_infop)fn_png_create_info_struct (png_ptr);
4ef0d4d0
KS
6038 if (!info_ptr)
6039 {
6040 fn_png_destroy_read_struct (&png_ptr, NULL, NULL);
6041 if (fp) fclose (fp);
6042 UNGCPRO;
6043 return 0;
6044 }
6045
2e09fef1
EZ
6046 /* Casting return value avoids a GCC warning on W32. */
6047 end_info = (png_infop)fn_png_create_info_struct (png_ptr);
4ef0d4d0
KS
6048 if (!end_info)
6049 {
6050 fn_png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
6051 if (fp) fclose (fp);
6052 UNGCPRO;
6053 return 0;
6054 }
6055
6056 /* Set error jump-back. We come back here when the PNG library
6057 detects an error. */
6058 if (setjmp (png_ptr->jmpbuf))
6059 {
6060 error:
6061 if (png_ptr)
6062 fn_png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
6063 xfree (pixels);
6064 xfree (rows);
6065 if (fp) fclose (fp);
6066 UNGCPRO;
6067 return 0;
6068 }
6069
6070 /* Read image info. */
6071 if (!NILP (specified_data))
6072 fn_png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
6073 else
9a22a004 6074 fn_png_set_read_fn (png_ptr, (void *) fp, png_read_from_file);
4ef0d4d0
KS
6075
6076 fn_png_set_sig_bytes (png_ptr, sizeof sig);
6077 fn_png_read_info (png_ptr, info_ptr);
6078 fn_png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
6079 &interlace_type, NULL, NULL);
6080
f1f25b99
CY
6081 if (!check_image_size (f, width, height))
6082 goto error;
6083
4ef0d4d0
KS
6084 /* If image contains simply transparency data, we prefer to
6085 construct a clipping mask. */
6086 if (fn_png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
6087 transparent_p = 1;
6088 else
6089 transparent_p = 0;
6090
6091 /* This function is easier to write if we only have to handle
6092 one data format: RGB or RGBA with 8 bits per channel. Let's
6093 transform other formats into that format. */
6094
6095 /* Strip more than 8 bits per channel. */
6096 if (bit_depth == 16)
6097 fn_png_set_strip_16 (png_ptr);
6098
6099 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
6100 if available. */
6101 fn_png_set_expand (png_ptr);
6102
6103 /* Convert grayscale images to RGB. */
6104 if (color_type == PNG_COLOR_TYPE_GRAY
6105 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
6106 fn_png_set_gray_to_rgb (png_ptr);
6107
4ef0d4d0
KS
6108 /* Handle alpha channel by combining the image with a background
6109 color. Do this only if a real alpha channel is supplied. For
6110 simple transparency, we prefer a clipping mask. */
6111 if (!transparent_p)
6112 {
917ac1a9 6113 /* png_color_16 *image_bg; */
4ef0d4d0
KS
6114 Lisp_Object specified_bg
6115 = image_spec_value (img->spec, QCbackground, NULL);
c4f13f44 6116 int shift = (bit_depth == 16) ? 0 : 8;
4ef0d4d0
KS
6117
6118 if (STRINGP (specified_bg))
6119 /* The user specified `:background', use that. */
6120 {
4ef0d4d0
KS
6121 XColor color;
6122 if (x_defined_color (f, SDATA (specified_bg), &color, 0))
6123 {
6124 png_color_16 user_bg;
6125
6126 bzero (&user_bg, sizeof user_bg);
c4f13f44
CY
6127 user_bg.red = color.red >> shift;
6128 user_bg.green = color.green >> shift;
6129 user_bg.blue = color.blue >> shift;
4ef0d4d0
KS
6130
6131 fn_png_set_background (png_ptr, &user_bg,
6132 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
6133 }
6134 }
4ef0d4d0
KS
6135 else
6136 {
c4f13f44
CY
6137 /* We use the current frame background, ignoring any default
6138 background color set by the image. */
8b7d0a16 6139#if defined (HAVE_X_WINDOWS) || defined (HAVE_NTGUI)
4ef0d4d0
KS
6140 XColor color;
6141 png_color_16 frame_background;
6142
6143 color.pixel = FRAME_BACKGROUND_PIXEL (f);
6144 x_query_color (f, &color);
6145
6146 bzero (&frame_background, sizeof frame_background);
c4f13f44
CY
6147 frame_background.red = color.red >> shift;
6148 frame_background.green = color.green >> shift;
6149 frame_background.blue = color.blue >> shift;
4ef0d4d0
KS
6150#endif /* HAVE_X_WINDOWS */
6151
4ef0d4d0
KS
6152 fn_png_set_background (png_ptr, &frame_background,
6153 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
6154 }
6155 }
6156
6157 /* Update info structure. */
6158 fn_png_read_update_info (png_ptr, info_ptr);
6159
6160 /* Get number of channels. Valid values are 1 for grayscale images
6161 and images with a palette, 2 for grayscale images with transparency
6162 information (alpha channel), 3 for RGB images, and 4 for RGB
6163 images with alpha channel, i.e. RGBA. If conversions above were
6164 sufficient we should only have 3 or 4 channels here. */
6165 channels = fn_png_get_channels (png_ptr, info_ptr);
6166 xassert (channels == 3 || channels == 4);
6167
6168 /* Number of bytes needed for one row of the image. */
6169 row_bytes = fn_png_get_rowbytes (png_ptr, info_ptr);
6170
6171 /* Allocate memory for the image. */
6172 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
6173 rows = (png_byte **) xmalloc (height * sizeof *rows);
6174 for (i = 0; i < height; ++i)
6175 rows[i] = pixels + i * row_bytes;
6176
6177 /* Read the entire image. */
6178 fn_png_read_image (png_ptr, rows);
6179 fn_png_read_end (png_ptr, info_ptr);
6180 if (fp)
6181 {
6182 fclose (fp);
6183 fp = NULL;
6184 }
6185
6186 /* Create the X image and pixmap. */
6187 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
6188 &img->pixmap))
6189 goto error;
6190
6191 /* Create an image and pixmap serving as mask if the PNG image
6192 contains an alpha channel. */
6193 if (channels == 4
6194 && !transparent_p
6195 && !x_create_x_image_and_pixmap (f, width, height, 1,
6196 &mask_img, &img->mask))
6197 {
6198 x_destroy_x_image (ximg);
6199 Free_Pixmap (FRAME_X_DISPLAY (f), img->pixmap);
6200 img->pixmap = NO_PIXMAP;
6201 goto error;
6202 }
6203
6204 /* Fill the X image and mask from PNG data. */
6205 init_color_table ();
6206
6207 for (y = 0; y < height; ++y)
6208 {
6209 png_byte *p = rows[y];
6210
6211 for (x = 0; x < width; ++x)
6212 {
6213 unsigned r, g, b;
6214
6215 r = *p++ << 8;
6216 g = *p++ << 8;
6217 b = *p++ << 8;
6218 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
6219 /* An alpha channel, aka mask channel, associates variable
6220 transparency with an image. Where other image formats
6221 support binary transparency---fully transparent or fully
6222 opaque---PNG allows up to 254 levels of partial transparency.
6223 The PNG library implements partial transparency by combining
6224 the image with a specified background color.
6225
6226 I'm not sure how to handle this here nicely: because the
6227 background on which the image is displayed may change, for
6228 real alpha channel support, it would be necessary to create
6229 a new image for each possible background.
6230
6231 What I'm doing now is that a mask is created if we have
6232 boolean transparency information. Otherwise I'm using
6233 the frame's background color to combine the image with. */
6234
6235 if (channels == 4)
6236 {
6237 if (mask_img)
9ecf6403 6238 XPutPixel (mask_img, x, y, *p > 0 ? PIX_MASK_DRAW : PIX_MASK_RETAIN);
4ef0d4d0
KS
6239 ++p;
6240 }
6241 }
6242 }
6243
6244 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
6245 /* Set IMG's background color from the PNG image, unless the user
6246 overrode it. */
6247 {
6248 png_color_16 *bg;
6249 if (fn_png_get_bKGD (png_ptr, info_ptr, &bg))
6250 {
6251 img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue);
6252 img->background_valid = 1;
6253 }
6254 }
6255
6256#ifdef COLOR_TABLE_SUPPORT
6257 /* Remember colors allocated for this image. */
6258 img->colors = colors_in_color_table (&img->ncolors);
6259 free_color_table ();
6260#endif /* COLOR_TABLE_SUPPORT */
6261
6262 /* Clean up. */
6263 fn_png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
6264 xfree (rows);
6265 xfree (pixels);
6266
6267 img->width = width;
6268 img->height = height;
6269
2e09fef1
EZ
6270 /* Maybe fill in the background field while we have ximg handy.
6271 Casting avoids a GCC warning. */
6272 IMAGE_BACKGROUND (img, f, (XImagePtr_or_DC)ximg);
4ef0d4d0
KS
6273
6274 /* Put the image into the pixmap, then free the X image and its buffer. */
6275 x_put_x_image (f, ximg, img->pixmap, width, height);
6276 x_destroy_x_image (ximg);
6277
6278 /* Same for the mask. */
6279 if (mask_img)
6280 {
2e09fef1
EZ
6281 /* Fill in the background_transparent field while we have the
6282 mask handy. Casting avoids a GCC warning. */
6283 image_background_transparent (img, f, (XImagePtr_or_DC)mask_img);
4ef0d4d0
KS
6284
6285 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
6286 x_destroy_x_image (mask_img);
6287 }
6288
6289 UNGCPRO;
6290 return 1;
6291}
6292
6293#else /* HAVE_PNG */
6294
edfda783
AR
6295#ifdef HAVE_NS
6296static int
6297png_load (struct frame *f, struct image *img)
6298{
6299 return ns_load_image(f, img,
6300 image_spec_value (img->spec, QCfile, NULL),
6301 image_spec_value (img->spec, QCdata, NULL));
6302}
6303#endif /* HAVE_NS */
6304
6305
4ef0d4d0
KS
6306#endif /* !HAVE_PNG */
6307
6308
6309\f
6310/***********************************************************************
6311 JPEG
6312 ***********************************************************************/
6313
9e2a2647 6314#if defined (HAVE_JPEG) || defined (HAVE_NS)
4ef0d4d0
KS
6315
6316static int jpeg_image_p P_ ((Lisp_Object object));
6317static int jpeg_load P_ ((struct frame *f, struct image *img));
6318
6319/* The symbol `jpeg' identifying images of this type. */
6320
6321Lisp_Object Qjpeg;
6322
6323/* Indices of image specification fields in gs_format, below. */
6324
6325enum jpeg_keyword_index
6326{
6327 JPEG_TYPE,
6328 JPEG_DATA,
6329 JPEG_FILE,
6330 JPEG_ASCENT,
6331 JPEG_MARGIN,
6332 JPEG_RELIEF,
6333 JPEG_ALGORITHM,
6334 JPEG_HEURISTIC_MASK,
6335 JPEG_MASK,
6336 JPEG_BACKGROUND,
6337 JPEG_LAST
6338};
6339
6340/* Vector of image_keyword structures describing the format
6341 of valid user-defined image specifications. */
6342
6343static struct image_keyword jpeg_format[JPEG_LAST] =
6344{
6345 {":type", IMAGE_SYMBOL_VALUE, 1},
6346 {":data", IMAGE_STRING_VALUE, 0},
6347 {":file", IMAGE_STRING_VALUE, 0},
6348 {":ascent", IMAGE_ASCENT_VALUE, 0},
6349 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6350 {":relief", IMAGE_INTEGER_VALUE, 0},
6351 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6352 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6353 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6354 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6355};
6356
6357/* Structure describing the image type `jpeg'. */
6358
6359static struct image_type jpeg_type =
6360{
6361 &Qjpeg,
6362 jpeg_image_p,
6363 jpeg_load,
6364 x_clear_image,
6365 NULL
6366};
6367
6368/* Return non-zero if OBJECT is a valid JPEG image specification. */
6369
6370static int
6371jpeg_image_p (object)
6372 Lisp_Object object;
6373{
6374 struct image_keyword fmt[JPEG_LAST];
6375
6376 bcopy (jpeg_format, fmt, sizeof fmt);
6377
6378 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg))
6379 return 0;
6380
6381 /* Must specify either the :data or :file keyword. */
6382 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
6383}
6384
9e2a2647 6385#endif /* HAVE_JPEG || HAVE_NS */
4ef0d4d0
KS
6386
6387#ifdef HAVE_JPEG
6388
6389/* Work around a warning about HAVE_STDLIB_H being redefined in
6390 jconfig.h. */
6391#ifdef HAVE_STDLIB_H
6392#define HAVE_STDLIB_H_1
6393#undef HAVE_STDLIB_H
6394#endif /* HAVE_STLIB_H */
6395
66354420 6396#if defined (HAVE_NTGUI) && !defined (__WIN32__)
28893db2
JB
6397/* In older releases of the jpeg library, jpeglib.h will define boolean
6398 differently depending on __WIN32__, so make sure it is defined. */
66354420
JR
6399#define __WIN32__ 1
6400#endif
6401
4ef0d4d0
KS
6402#include <jpeglib.h>
6403#include <jerror.h>
6404#include <setjmp.h>
6405
6406#ifdef HAVE_STLIB_H_1
6407#define HAVE_STDLIB_H 1
6408#endif
6409
6410#ifdef HAVE_NTGUI
6411
6412/* JPEG library details. */
6413DEF_IMGLIB_FN (jpeg_CreateDecompress);
6414DEF_IMGLIB_FN (jpeg_start_decompress);
6415DEF_IMGLIB_FN (jpeg_finish_decompress);
6416DEF_IMGLIB_FN (jpeg_destroy_decompress);
6417DEF_IMGLIB_FN (jpeg_read_header);
6418DEF_IMGLIB_FN (jpeg_read_scanlines);
4ef0d4d0
KS
6419DEF_IMGLIB_FN (jpeg_std_error);
6420DEF_IMGLIB_FN (jpeg_resync_to_restart);
6421
6422static int
0855eb52 6423init_jpeg_functions (Lisp_Object libraries)
4ef0d4d0
KS
6424{
6425 HMODULE library;
6426
0855eb52 6427 if (!(library = w32_delayed_load (libraries, Qjpeg)))
4ef0d4d0
KS
6428 return 0;
6429
6430 LOAD_IMGLIB_FN (library, jpeg_finish_decompress);
6431 LOAD_IMGLIB_FN (library, jpeg_read_scanlines);
6432 LOAD_IMGLIB_FN (library, jpeg_start_decompress);
6433 LOAD_IMGLIB_FN (library, jpeg_read_header);
4ef0d4d0
KS
6434 LOAD_IMGLIB_FN (library, jpeg_CreateDecompress);
6435 LOAD_IMGLIB_FN (library, jpeg_destroy_decompress);
6436 LOAD_IMGLIB_FN (library, jpeg_std_error);
6437 LOAD_IMGLIB_FN (library, jpeg_resync_to_restart);
6438 return 1;
6439}
6440
6441/* Wrapper since we can't directly assign the function pointer
6442 to another function pointer that was declared more completely easily. */
6443static boolean
5fc9fdeb 6444jpeg_resync_to_restart_wrapper (cinfo, desired)
4ef0d4d0
KS
6445 j_decompress_ptr cinfo;
6446 int desired;
6447{
6448 return fn_jpeg_resync_to_restart (cinfo, desired);
6449}
6450
6451#else
6452
6453#define fn_jpeg_CreateDecompress(a,b,c) jpeg_create_decompress(a)
6454#define fn_jpeg_start_decompress jpeg_start_decompress
6455#define fn_jpeg_finish_decompress jpeg_finish_decompress
6456#define fn_jpeg_destroy_decompress jpeg_destroy_decompress
6457#define fn_jpeg_read_header jpeg_read_header
6458#define fn_jpeg_read_scanlines jpeg_read_scanlines
4ef0d4d0
KS
6459#define fn_jpeg_std_error jpeg_std_error
6460#define jpeg_resync_to_restart_wrapper jpeg_resync_to_restart
6461
6462#endif /* HAVE_NTGUI */
6463
6464struct my_jpeg_error_mgr
6465{
6466 struct jpeg_error_mgr pub;
6467 jmp_buf setjmp_buffer;
6468};
6469
6470
6471static void
6472my_error_exit (cinfo)
6473 j_common_ptr cinfo;
6474{
6475 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
6476 longjmp (mgr->setjmp_buffer, 1);
6477}
6478
6479
6480/* Init source method for JPEG data source manager. Called by
6481 jpeg_read_header() before any data is actually read. See
6482 libjpeg.doc from the JPEG lib distribution. */
6483
6484static void
b25a72ab
JB
6485our_common_init_source (cinfo)
6486 j_decompress_ptr cinfo;
6487{
6488}
6489
6490
6491/* Method to terminate data source. Called by
6492 jpeg_finish_decompress() after all data has been processed. */
6493
6494static void
6495our_common_term_source (cinfo)
4ef0d4d0
KS
6496 j_decompress_ptr cinfo;
6497{
6498}
6499
6500
6501/* Fill input buffer method for JPEG data source manager. Called
6502 whenever more data is needed. We read the whole image in one step,
6503 so this only adds a fake end of input marker at the end. */
6504
5a1539f3 6505static JOCTET our_memory_buffer[2];
aca946f3 6506
4ef0d4d0 6507static boolean
b25a72ab 6508our_memory_fill_input_buffer (cinfo)
4ef0d4d0
KS
6509 j_decompress_ptr cinfo;
6510{
6511 /* Insert a fake EOI marker. */
6512 struct jpeg_source_mgr *src = cinfo->src;
4ef0d4d0 6513
5a1539f3
MB
6514 our_memory_buffer[0] = (JOCTET) 0xFF;
6515 our_memory_buffer[1] = (JOCTET) JPEG_EOI;
4ef0d4d0 6516
5a1539f3 6517 src->next_input_byte = our_memory_buffer;
4ef0d4d0 6518 src->bytes_in_buffer = 2;
e0e30823 6519 return 1;
4ef0d4d0
KS
6520}
6521
6522
6523/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
6524 is the JPEG data source manager. */
6525
6526static void
b25a72ab 6527our_memory_skip_input_data (cinfo, num_bytes)
4ef0d4d0
KS
6528 j_decompress_ptr cinfo;
6529 long num_bytes;
6530{
6531 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
6532
6533 if (src)
6534 {
6535 if (num_bytes > src->bytes_in_buffer)
6536 ERREXIT (cinfo, JERR_INPUT_EOF);
6537
6538 src->bytes_in_buffer -= num_bytes;
6539 src->next_input_byte += num_bytes;
6540 }
6541}
6542
6543
4ef0d4d0
KS
6544/* Set up the JPEG lib for reading an image from DATA which contains
6545 LEN bytes. CINFO is the decompression info structure created for
6546 reading the image. */
6547
6548static void
6549jpeg_memory_src (cinfo, data, len)
6550 j_decompress_ptr cinfo;
6551 JOCTET *data;
6552 unsigned int len;
6553{
6554 struct jpeg_source_mgr *src;
6555
6556 if (cinfo->src == NULL)
6557 {
6558 /* First time for this JPEG object? */
6559 cinfo->src = (struct jpeg_source_mgr *)
6560 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
6561 sizeof (struct jpeg_source_mgr));
6562 src = (struct jpeg_source_mgr *) cinfo->src;
6563 src->next_input_byte = data;
6564 }
6565
6566 src = (struct jpeg_source_mgr *) cinfo->src;
b25a72ab
JB
6567 src->init_source = our_common_init_source;
6568 src->fill_input_buffer = our_memory_fill_input_buffer;
6569 src->skip_input_data = our_memory_skip_input_data;
4ef0d4d0 6570 src->resync_to_restart = jpeg_resync_to_restart_wrapper; /* Use default method. */
b25a72ab 6571 src->term_source = our_common_term_source;
4ef0d4d0
KS
6572 src->bytes_in_buffer = len;
6573 src->next_input_byte = data;
6574}
6575
6576
b25a72ab
JB
6577struct jpeg_stdio_mgr
6578{
6579 struct jpeg_source_mgr mgr;
6580 boolean finished;
6581 FILE *file;
6582 JOCTET *buffer;
6583};
6584
6585
6586/* Size of buffer to read JPEG from file.
6587 Not too big, as we want to use alloc_small. */
6588#define JPEG_STDIO_BUFFER_SIZE 8192
6589
6590
6591/* Fill input buffer method for JPEG data source manager. Called
6592 whenever more data is needed. The data is read from a FILE *. */
6593
6594static boolean
6595our_stdio_fill_input_buffer (cinfo)
6596 j_decompress_ptr cinfo;
6597{
6598 struct jpeg_stdio_mgr *src;
6599
6600 src = (struct jpeg_stdio_mgr *) cinfo->src;
6601 if (!src->finished)
6602 {
6603 size_t bytes;
6604
6605 bytes = fread (src->buffer, 1, JPEG_STDIO_BUFFER_SIZE, src->file);
6606 if (bytes > 0)
6607 src->mgr.bytes_in_buffer = bytes;
6608 else
6609 {
6610 WARNMS (cinfo, JWRN_JPEG_EOF);
6611 src->finished = 1;
6612 src->buffer[0] = (JOCTET) 0xFF;
6613 src->buffer[1] = (JOCTET) JPEG_EOI;
6614 src->mgr.bytes_in_buffer = 2;
6615 }
6616 src->mgr.next_input_byte = src->buffer;
6617 }
6618
6619 return 1;
6620}
6621
6622
6623/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
6624 is the JPEG data source manager. */
6625
6626static void
6627our_stdio_skip_input_data (cinfo, num_bytes)
6628 j_decompress_ptr cinfo;
6629 long num_bytes;
6630{
6631 struct jpeg_stdio_mgr *src;
6632 src = (struct jpeg_stdio_mgr *) cinfo->src;
6633
6634 while (num_bytes > 0 && !src->finished)
6635 {
6636 if (num_bytes <= src->mgr.bytes_in_buffer)
6637 {
6638 src->mgr.bytes_in_buffer -= num_bytes;
6639 src->mgr.next_input_byte += num_bytes;
6640 break;
6641 }
6642 else
6643 {
6644 num_bytes -= src->mgr.bytes_in_buffer;
6645 src->mgr.bytes_in_buffer = 0;
6646 src->mgr.next_input_byte = NULL;
6647
6648 our_stdio_fill_input_buffer (cinfo);
6649 }
6650 }
6651}
6652
6653
6654/* Set up the JPEG lib for reading an image from a FILE *.
6655 CINFO is the decompression info structure created for
6656 reading the image. */
6657
6658static void
6659jpeg_file_src (cinfo, fp)
6660 j_decompress_ptr cinfo;
6661 FILE *fp;
6662{
6663 struct jpeg_stdio_mgr *src;
6664
6665 if (cinfo->src != NULL)
6666 src = (struct jpeg_stdio_mgr *) cinfo->src;
6667 else
6668 {
6669 /* First time for this JPEG object? */
6670 cinfo->src = (struct jpeg_source_mgr *)
6671 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
6672 sizeof (struct jpeg_stdio_mgr));
6673 src = (struct jpeg_stdio_mgr *) cinfo->src;
6674 src->buffer = (JOCTET *)
6675 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
6676 JPEG_STDIO_BUFFER_SIZE);
6677 }
6678
6679 src->file = fp;
6680 src->finished = 0;
6681 src->mgr.init_source = our_common_init_source;
6682 src->mgr.fill_input_buffer = our_stdio_fill_input_buffer;
6683 src->mgr.skip_input_data = our_stdio_skip_input_data;
6684 src->mgr.resync_to_restart = jpeg_resync_to_restart_wrapper; /* Use default method. */
6685 src->mgr.term_source = our_common_term_source;
6686 src->mgr.bytes_in_buffer = 0;
6687 src->mgr.next_input_byte = NULL;
6688}
6689
6690
4ef0d4d0
KS
6691/* Load image IMG for use on frame F. Patterned after example.c
6692 from the JPEG lib. */
6693
6694static int
6695jpeg_load (f, img)
6696 struct frame *f;
6697 struct image *img;
6698{
6699 struct jpeg_decompress_struct cinfo;
6700 struct my_jpeg_error_mgr mgr;
6701 Lisp_Object file, specified_file;
6702 Lisp_Object specified_data;
6703 FILE * volatile fp = NULL;
6704 JSAMPARRAY buffer;
6705 int row_stride, x, y;
6706 XImagePtr ximg = NULL;
6707 int rc;
6708 unsigned long *colors;
6709 int width, height;
6710 struct gcpro gcpro1;
6711
6712 /* Open the JPEG file. */
6713 specified_file = image_spec_value (img->spec, QCfile, NULL);
6714 specified_data = image_spec_value (img->spec, QCdata, NULL);
6715 file = Qnil;
6716 GCPRO1 (file);
6717
6718 if (NILP (specified_data))
6719 {
6720 file = x_find_image_file (specified_file);
6721 if (!STRINGP (file))
6722 {
6723 image_error ("Cannot find image file `%s'", specified_file, Qnil);
6724 UNGCPRO;
6725 return 0;
6726 }
6727
6728 fp = fopen (SDATA (file), "rb");
6729 if (fp == NULL)
6730 {
6731 image_error ("Cannot open `%s'", file, Qnil);
6732 UNGCPRO;
6733 return 0;
6734 }
6735 }
6736
6737 /* Customize libjpeg's error handling to call my_error_exit when an
2e09fef1
EZ
6738 error is detected. This function will perform a longjmp.
6739 Casting return value avoids a GCC warning on W32. */
6740 cinfo.err = (struct jpeg_error_mgr *)fn_jpeg_std_error (&mgr.pub);
4ef0d4d0
KS
6741 mgr.pub.error_exit = my_error_exit;
6742
6743 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
6744 {
6745 if (rc == 1)
6746 {
6747 /* Called from my_error_exit. Display a JPEG error. */
6748 char buffer[JMSG_LENGTH_MAX];
6749 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
6750 image_error ("Error reading JPEG image `%s': %s", img->spec,
6751 build_string (buffer));
6752 }
6753
6754 /* Close the input file and destroy the JPEG object. */
6755 if (fp)
6756 fclose ((FILE *) fp);
6757 fn_jpeg_destroy_decompress (&cinfo);
6758
6759 /* If we already have an XImage, free that. */
6760 x_destroy_x_image (ximg);
6761
6762 /* Free pixmap and colors. */
6763 x_clear_image (f, img);
6764
6765 UNGCPRO;
6766 return 0;
6767 }
6768
6769 /* Create the JPEG decompression object. Let it read from fp.
6770 Read the JPEG image header. */
6771 fn_jpeg_CreateDecompress (&cinfo, JPEG_LIB_VERSION, sizeof (cinfo));
6772
6773 if (NILP (specified_data))
b25a72ab 6774 jpeg_file_src (&cinfo, (FILE *) fp);
4ef0d4d0
KS
6775 else
6776 jpeg_memory_src (&cinfo, SDATA (specified_data),
6777 SBYTES (specified_data));
6778
e0e30823 6779 fn_jpeg_read_header (&cinfo, 1);
4ef0d4d0
KS
6780
6781 /* Customize decompression so that color quantization will be used.
6782 Start decompression. */
e0e30823 6783 cinfo.quantize_colors = 1;
4ef0d4d0
KS
6784 fn_jpeg_start_decompress (&cinfo);
6785 width = img->width = cinfo.output_width;
6786 height = img->height = cinfo.output_height;
6787
f1f25b99
CY
6788 if (!check_image_size (f, width, height))
6789 {
6790 image_error ("Invalid image size", Qnil, Qnil);
6791 longjmp (mgr.setjmp_buffer, 2);
6792 }
6793
4ef0d4d0
KS
6794 /* Create X image and pixmap. */
6795 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
6796 longjmp (mgr.setjmp_buffer, 2);
6797
6798 /* Allocate colors. When color quantization is used,
6799 cinfo.actual_number_of_colors has been set with the number of
6800 colors generated, and cinfo.colormap is a two-dimensional array
6801 of color indices in the range 0..cinfo.actual_number_of_colors.
6802 No more than 255 colors will be generated. */
6803 {
6804 int i, ir, ig, ib;
6805
6806 if (cinfo.out_color_components > 2)
6807 ir = 0, ig = 1, ib = 2;
6808 else if (cinfo.out_color_components > 1)
6809 ir = 0, ig = 1, ib = 0;
6810 else
6811 ir = 0, ig = 0, ib = 0;
6812
6813 /* Use the color table mechanism because it handles colors that
6814 cannot be allocated nicely. Such colors will be replaced with
6815 a default color, and we don't have to care about which colors
6816 can be freed safely, and which can't. */
6817 init_color_table ();
6818 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
6819 * sizeof *colors);
6820
6821 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
6822 {
6823 /* Multiply RGB values with 255 because X expects RGB values
6824 in the range 0..0xffff. */
6825 int r = cinfo.colormap[ir][i] << 8;
6826 int g = cinfo.colormap[ig][i] << 8;
6827 int b = cinfo.colormap[ib][i] << 8;
6828 colors[i] = lookup_rgb_color (f, r, g, b);
6829 }
6830
6831#ifdef COLOR_TABLE_SUPPORT
6832 /* Remember those colors actually allocated. */
6833 img->colors = colors_in_color_table (&img->ncolors);
6834 free_color_table ();
6835#endif /* COLOR_TABLE_SUPPORT */
6836 }
6837
6838 /* Read pixels. */
6839 row_stride = width * cinfo.output_components;
6840 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
6841 row_stride, 1);
6842 for (y = 0; y < height; ++y)
6843 {
6844 fn_jpeg_read_scanlines (&cinfo, buffer, 1);
6845 for (x = 0; x < cinfo.output_width; ++x)
6846 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
6847 }
6848
6849 /* Clean up. */
6850 fn_jpeg_finish_decompress (&cinfo);
6851 fn_jpeg_destroy_decompress (&cinfo);
6852 if (fp)
6853 fclose ((FILE *) fp);
6854
6855 /* Maybe fill in the background field while we have ximg handy. */
6856 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
2e09fef1
EZ
6857 /* Casting avoids a GCC warning. */
6858 IMAGE_BACKGROUND (img, f, (XImagePtr_or_DC)ximg);
4ef0d4d0
KS
6859
6860 /* Put the image into the pixmap. */
6861 x_put_x_image (f, ximg, img->pixmap, width, height);
6862 x_destroy_x_image (ximg);
6863 UNGCPRO;
6864 return 1;
6865}
6866
6867#else /* HAVE_JPEG */
6868
edfda783
AR
6869#ifdef HAVE_NS
6870static int
6871jpeg_load (struct frame *f, struct image *img)
6872{
6873 return ns_load_image(f, img,
6874 image_spec_value (img->spec, QCfile, NULL),
6875 image_spec_value (img->spec, QCdata, NULL));
6876}
6877#endif /* HAVE_NS */
6878
4ef0d4d0
KS
6879#endif /* !HAVE_JPEG */
6880
6881
6882\f
6883/***********************************************************************
6884 TIFF
6885 ***********************************************************************/
6886
9e2a2647 6887#if defined (HAVE_TIFF) || defined (HAVE_NS)
4ef0d4d0
KS
6888
6889static int tiff_image_p P_ ((Lisp_Object object));
6890static int tiff_load P_ ((struct frame *f, struct image *img));
6891
6892/* The symbol `tiff' identifying images of this type. */
6893
6894Lisp_Object Qtiff;
6895
6896/* Indices of image specification fields in tiff_format, below. */
6897
6898enum tiff_keyword_index
6899{
6900 TIFF_TYPE,
6901 TIFF_DATA,
6902 TIFF_FILE,
6903 TIFF_ASCENT,
6904 TIFF_MARGIN,
6905 TIFF_RELIEF,
6906 TIFF_ALGORITHM,
6907 TIFF_HEURISTIC_MASK,
6908 TIFF_MASK,
6909 TIFF_BACKGROUND,
58279503 6910 TIFF_INDEX,
4ef0d4d0
KS
6911 TIFF_LAST
6912};
6913
6914/* Vector of image_keyword structures describing the format
6915 of valid user-defined image specifications. */
6916
6917static struct image_keyword tiff_format[TIFF_LAST] =
6918{
6919 {":type", IMAGE_SYMBOL_VALUE, 1},
6920 {":data", IMAGE_STRING_VALUE, 0},
6921 {":file", IMAGE_STRING_VALUE, 0},
6922 {":ascent", IMAGE_ASCENT_VALUE, 0},
6923 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6924 {":relief", IMAGE_INTEGER_VALUE, 0},
6925 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6926 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6927 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
58279503
JR
6928 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
6929 {":index", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}
4ef0d4d0
KS
6930};
6931
6932/* Structure describing the image type `tiff'. */
6933
6934static struct image_type tiff_type =
6935{
6936 &Qtiff,
6937 tiff_image_p,
6938 tiff_load,
6939 x_clear_image,
6940 NULL
6941};
6942
6943/* Return non-zero if OBJECT is a valid TIFF image specification. */
6944
6945static int
6946tiff_image_p (object)
6947 Lisp_Object object;
6948{
6949 struct image_keyword fmt[TIFF_LAST];
6950 bcopy (tiff_format, fmt, sizeof fmt);
6951
6952 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff))
6953 return 0;
6954
6955 /* Must specify either the :data or :file keyword. */
6956 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
6957}
6958
9e2a2647 6959#endif /* HAVE_TIFF || HAVE_NS */
4ef0d4d0
KS
6960
6961#ifdef HAVE_TIFF
6962
6963#include <tiffio.h>
6964
6965#ifdef HAVE_NTGUI
6966
6967/* TIFF library details. */
6968DEF_IMGLIB_FN (TIFFSetErrorHandler);
6969DEF_IMGLIB_FN (TIFFSetWarningHandler);
6970DEF_IMGLIB_FN (TIFFOpen);
6971DEF_IMGLIB_FN (TIFFClientOpen);
6972DEF_IMGLIB_FN (TIFFGetField);
6973DEF_IMGLIB_FN (TIFFReadRGBAImage);
6974DEF_IMGLIB_FN (TIFFClose);
58279503 6975DEF_IMGLIB_FN (TIFFSetDirectory);
4ef0d4d0
KS
6976
6977static int
0855eb52 6978init_tiff_functions (Lisp_Object libraries)
4ef0d4d0
KS
6979{
6980 HMODULE library;
6981
0855eb52 6982 if (!(library = w32_delayed_load (libraries, Qtiff)))
4ef0d4d0
KS
6983 return 0;
6984
6985 LOAD_IMGLIB_FN (library, TIFFSetErrorHandler);
6986 LOAD_IMGLIB_FN (library, TIFFSetWarningHandler);
6987 LOAD_IMGLIB_FN (library, TIFFOpen);
6988 LOAD_IMGLIB_FN (library, TIFFClientOpen);
6989 LOAD_IMGLIB_FN (library, TIFFGetField);
6990 LOAD_IMGLIB_FN (library, TIFFReadRGBAImage);
6991 LOAD_IMGLIB_FN (library, TIFFClose);
58279503 6992 LOAD_IMGLIB_FN (library, TIFFSetDirectory);
4ef0d4d0
KS
6993 return 1;
6994}
6995
6996#else
6997
6998#define fn_TIFFSetErrorHandler TIFFSetErrorHandler
6999#define fn_TIFFSetWarningHandler TIFFSetWarningHandler
7000#define fn_TIFFOpen TIFFOpen
7001#define fn_TIFFClientOpen TIFFClientOpen
7002#define fn_TIFFGetField TIFFGetField
7003#define fn_TIFFReadRGBAImage TIFFReadRGBAImage
7004#define fn_TIFFClose TIFFClose
58279503 7005#define fn_TIFFSetDirectory TIFFSetDirectory
4ef0d4d0
KS
7006#endif /* HAVE_NTGUI */
7007
7008
7009/* Reading from a memory buffer for TIFF images Based on the PNG
7010 memory source, but we have to provide a lot of extra functions.
7011 Blah.
7012
7013 We really only need to implement read and seek, but I am not
7014 convinced that the TIFF library is smart enough not to destroy
7015 itself if we only hand it the function pointers we need to
7016 override. */
7017
7018typedef struct
7019{
7020 unsigned char *bytes;
7021 size_t len;
7022 int index;
7023}
7024tiff_memory_source;
7025
7026static size_t
7027tiff_read_from_memory (data, buf, size)
7028 thandle_t data;
7029 tdata_t buf;
7030 tsize_t size;
7031{
7032 tiff_memory_source *src = (tiff_memory_source *) data;
7033
7034 if (size > src->len - src->index)
7035 return (size_t) -1;
7036 bcopy (src->bytes + src->index, buf, size);
7037 src->index += size;
7038 return size;
7039}
7040
7041static size_t
7042tiff_write_from_memory (data, buf, size)
7043 thandle_t data;
7044 tdata_t buf;
7045 tsize_t size;
7046{
7047 return (size_t) -1;
7048}
7049
7050static toff_t
7051tiff_seek_in_memory (data, off, whence)
7052 thandle_t data;
7053 toff_t off;
7054 int whence;
7055{
7056 tiff_memory_source *src = (tiff_memory_source *) data;
7057 int idx;
7058
7059 switch (whence)
7060 {
7061 case SEEK_SET: /* Go from beginning of source. */
7062 idx = off;
7063 break;
7064
7065 case SEEK_END: /* Go from end of source. */
7066 idx = src->len + off;
7067 break;
7068
7069 case SEEK_CUR: /* Go from current position. */
7070 idx = src->index + off;
7071 break;
7072
7073 default: /* Invalid `whence'. */
7074 return -1;
7075 }
7076
7077 if (idx > src->len || idx < 0)
7078 return -1;
7079
7080 src->index = idx;
7081 return src->index;
7082}
7083
7084static int
7085tiff_close_memory (data)
7086 thandle_t data;
7087{
7088 /* NOOP */
7089 return 0;
7090}
7091
7092static int
7093tiff_mmap_memory (data, pbase, psize)
7094 thandle_t data;
7095 tdata_t *pbase;
7096 toff_t *psize;
7097{
7098 /* It is already _IN_ memory. */
7099 return 0;
7100}
7101
7102static void
7103tiff_unmap_memory (data, base, size)
7104 thandle_t data;
7105 tdata_t base;
7106 toff_t size;
7107{
7108 /* We don't need to do this. */
7109}
7110
7111static toff_t
7112tiff_size_of_memory (data)
7113 thandle_t data;
7114{
7115 return ((tiff_memory_source *) data)->len;
7116}
7117
7118
7119static void
7120tiff_error_handler (title, format, ap)
7121 const char *title, *format;
7122 va_list ap;
7123{
7124 char buf[512];
7125 int len;
7126
7127 len = sprintf (buf, "TIFF error: %s ", title);
7128 vsprintf (buf + len, format, ap);
7129 add_to_log (buf, Qnil, Qnil);
7130}
7131
7132
7133static void
7134tiff_warning_handler (title, format, ap)
7135 const char *title, *format;
7136 va_list ap;
7137{
7138 char buf[512];
7139 int len;
7140
7141 len = sprintf (buf, "TIFF warning: %s ", title);
7142 vsprintf (buf + len, format, ap);
7143 add_to_log (buf, Qnil, Qnil);
7144}
7145
7146
7147/* Load TIFF image IMG for use on frame F. Value is non-zero if
7148 successful. */
7149
7150static int
7151tiff_load (f, img)
7152 struct frame *f;
7153 struct image *img;
7154{
7155 Lisp_Object file, specified_file;
7156 Lisp_Object specified_data;
7157 TIFF *tiff;
58279503 7158 int width, height, x, y, count;
4ef0d4d0 7159 uint32 *buf;
58279503 7160 int rc, rc2;
4ef0d4d0
KS
7161 XImagePtr ximg;
7162 struct gcpro gcpro1;
7163 tiff_memory_source memsrc;
58279503 7164 Lisp_Object image;
4ef0d4d0
KS
7165
7166 specified_file = image_spec_value (img->spec, QCfile, NULL);
7167 specified_data = image_spec_value (img->spec, QCdata, NULL);
7168 file = Qnil;
7169 GCPRO1 (file);
7170
7171 fn_TIFFSetErrorHandler (tiff_error_handler);
7172 fn_TIFFSetWarningHandler (tiff_warning_handler);
7173
7174 if (NILP (specified_data))
7175 {
7176 /* Read from a file */
7177 file = x_find_image_file (specified_file);
7178 if (!STRINGP (file))
7179 {
7180 image_error ("Cannot find image file `%s'", specified_file, Qnil);
7181 UNGCPRO;
7182 return 0;
7183 }
7184
2e09fef1
EZ
7185 /* Try to open the image file. Casting return value avoids a
7186 GCC warning on W32. */
7187 tiff = (TIFF *)fn_TIFFOpen (SDATA (file), "r");
4ef0d4d0
KS
7188 if (tiff == NULL)
7189 {
7190 image_error ("Cannot open `%s'", file, Qnil);
7191 UNGCPRO;
7192 return 0;
7193 }
7194 }
7195 else
7196 {
7197 /* Memory source! */
7198 memsrc.bytes = SDATA (specified_data);
7199 memsrc.len = SBYTES (specified_data);
7200 memsrc.index = 0;
7201
2e09fef1
EZ
7202 /* Casting return value avoids a GCC warning on W32. */
7203 tiff = (TIFF *)fn_TIFFClientOpen ("memory_source", "r", &memsrc,
7204 (TIFFReadWriteProc) tiff_read_from_memory,
7205 (TIFFReadWriteProc) tiff_write_from_memory,
7206 tiff_seek_in_memory,
7207 tiff_close_memory,
7208 tiff_size_of_memory,
7209 tiff_mmap_memory,
7210 tiff_unmap_memory);
4ef0d4d0
KS
7211
7212 if (!tiff)
7213 {
7214 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
7215 UNGCPRO;
7216 return 0;
7217 }
7218 }
7219
58279503
JR
7220 image = image_spec_value (img->spec, QCindex, NULL);
7221 if (INTEGERP (image))
7222 {
7223 int ino = XFASTINT (image);
7224 if (!fn_TIFFSetDirectory (tiff, ino))
7225 {
7226 image_error ("Invalid image number `%s' in image `%s'",
7227 image, img->spec);
7228 fn_TIFFClose (tiff);
7229 UNGCPRO;
7230 return 0;
7231 }
7232 }
7233
4ef0d4d0
KS
7234 /* Get width and height of the image, and allocate a raster buffer
7235 of width x height 32-bit values. */
7236 fn_TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
7237 fn_TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
f1f25b99
CY
7238
7239 if (!check_image_size (f, width, height))
7240 {
7241 image_error ("Invalid image size", Qnil, Qnil);
58279503 7242 fn_TIFFClose (tiff);
f1f25b99
CY
7243 UNGCPRO;
7244 return 0;
7245 }
7246
4ef0d4d0
KS
7247 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
7248
7249 rc = fn_TIFFReadRGBAImage (tiff, width, height, buf, 0);
58279503
JR
7250
7251 /* Count the number of images in the file. */
7252 for (count = 1, rc2 = 1; rc2; count++)
7253 rc2 = fn_TIFFSetDirectory (tiff, count);
7254
7255 if (count > 1)
7256 img->data.lisp_val = Fcons (Qcount,
7257 Fcons (make_number (count),
7258 img->data.lisp_val));
7259
4ef0d4d0
KS
7260 fn_TIFFClose (tiff);
7261 if (!rc)
7262 {
7263 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
7264 xfree (buf);
7265 UNGCPRO;
7266 return 0;
7267 }
7268
7269 /* Create the X image and pixmap. */
7270 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
7271 {
7272 xfree (buf);
7273 UNGCPRO;
7274 return 0;
7275 }
7276
7277 /* Initialize the color table. */
7278 init_color_table ();
7279
7280 /* Process the pixel raster. Origin is in the lower-left corner. */
7281 for (y = 0; y < height; ++y)
7282 {
7283 uint32 *row = buf + y * width;
7284
7285 for (x = 0; x < width; ++x)
7286 {
7287 uint32 abgr = row[x];
7288 int r = TIFFGetR (abgr) << 8;
7289 int g = TIFFGetG (abgr) << 8;
7290 int b = TIFFGetB (abgr) << 8;
7291 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
7292 }
7293 }
7294
7295#ifdef COLOR_TABLE_SUPPORT
7296 /* Remember the colors allocated for the image. Free the color table. */
7297 img->colors = colors_in_color_table (&img->ncolors);
7298 free_color_table ();
7299#endif /* COLOR_TABLE_SUPPORT */
7300
7301 img->width = width;
7302 img->height = height;
7303
7304 /* Maybe fill in the background field while we have ximg handy. */
7305 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
2e09fef1
EZ
7306 /* Casting avoids a GCC warning on W32. */
7307 IMAGE_BACKGROUND (img, f, (XImagePtr_or_DC)ximg);
4ef0d4d0
KS
7308
7309 /* Put the image into the pixmap, then free the X image and its buffer. */
7310 x_put_x_image (f, ximg, img->pixmap, width, height);
7311 x_destroy_x_image (ximg);
7312 xfree (buf);
7313
7314 UNGCPRO;
7315 return 1;
7316}
7317
7318#else /* HAVE_TIFF */
7319
edfda783
AR
7320#ifdef HAVE_NS
7321static int
7322tiff_load (struct frame *f, struct image *img)
7323{
7324 return ns_load_image(f, img,
7325 image_spec_value (img->spec, QCfile, NULL),
7326 image_spec_value (img->spec, QCdata, NULL));
7327}
7328#endif /* HAVE_NS */
7329
4ef0d4d0
KS
7330#endif /* !HAVE_TIFF */
7331
7332
7333\f
7334/***********************************************************************
7335 GIF
7336 ***********************************************************************/
7337
9e2a2647 7338#if defined (HAVE_GIF) || defined (HAVE_NS)
4ef0d4d0
KS
7339
7340static int gif_image_p P_ ((Lisp_Object object));
7341static int gif_load P_ ((struct frame *f, struct image *img));
6ac3c7bb 7342static void gif_clear_image P_ ((struct frame *f, struct image *img));
4ef0d4d0
KS
7343
7344/* The symbol `gif' identifying images of this type. */
7345
7346Lisp_Object Qgif;
7347
7348/* Indices of image specification fields in gif_format, below. */
7349
7350enum gif_keyword_index
7351{
7352 GIF_TYPE,
7353 GIF_DATA,
7354 GIF_FILE,
7355 GIF_ASCENT,
7356 GIF_MARGIN,
7357 GIF_RELIEF,
7358 GIF_ALGORITHM,
7359 GIF_HEURISTIC_MASK,
7360 GIF_MASK,
7361 GIF_IMAGE,
7362 GIF_BACKGROUND,
7363 GIF_LAST
7364};
7365
7366/* Vector of image_keyword structures describing the format
7367 of valid user-defined image specifications. */
7368
7369static struct image_keyword gif_format[GIF_LAST] =
7370{
7371 {":type", IMAGE_SYMBOL_VALUE, 1},
7372 {":data", IMAGE_STRING_VALUE, 0},
7373 {":file", IMAGE_STRING_VALUE, 0},
7374 {":ascent", IMAGE_ASCENT_VALUE, 0},
7375 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
7376 {":relief", IMAGE_INTEGER_VALUE, 0},
7377 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7378 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7379 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
58279503 7380 {":index", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
4ef0d4d0
KS
7381 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
7382};
7383
7384/* Structure describing the image type `gif'. */
7385
7386static struct image_type gif_type =
7387{
7388 &Qgif,
7389 gif_image_p,
7390 gif_load,
6ac3c7bb 7391 gif_clear_image,
4ef0d4d0
KS
7392 NULL
7393};
7394
6ac3c7bb
KS
7395/* Free X resources of GIF image IMG which is used on frame F. */
7396
7397static void
7398gif_clear_image (f, img)
7399 struct frame *f;
7400 struct image *img;
7401{
7402 /* IMG->data.ptr_val may contain extension data. */
7403 img->data.lisp_val = Qnil;
7404 x_clear_image (f, img);
7405}
7406
4ef0d4d0
KS
7407/* Return non-zero if OBJECT is a valid GIF image specification. */
7408
7409static int
7410gif_image_p (object)
7411 Lisp_Object object;
7412{
7413 struct image_keyword fmt[GIF_LAST];
7414 bcopy (gif_format, fmt, sizeof fmt);
7415
7416 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif))
7417 return 0;
7418
7419 /* Must specify either the :data or :file keyword. */
7420 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
7421}
7422
9e2a2647 7423#endif /* HAVE_GIF */
4ef0d4d0
KS
7424
7425#ifdef HAVE_GIF
7426
9e2a2647 7427#if defined (HAVE_NTGUI)
2e09fef1
EZ
7428/* winuser.h might define DrawText to DrawTextA or DrawTextW.
7429 Undefine before redefining to avoid a preprocessor warning. */
7430#ifdef DrawText
7431#undef DrawText
7432#endif
4ef0d4d0
KS
7433/* avoid conflict with QuickdrawText.h */
7434#define DrawText gif_DrawText
7435#include <gif_lib.h>
7436#undef DrawText
7437
9e2a2647 7438#else /* HAVE_NTGUI */
4ef0d4d0
KS
7439
7440#include <gif_lib.h>
7441
9e2a2647 7442#endif /* HAVE_NTGUI */
4ef0d4d0
KS
7443
7444
7445#ifdef HAVE_NTGUI
7446
7447/* GIF library details. */
7448DEF_IMGLIB_FN (DGifCloseFile);
7449DEF_IMGLIB_FN (DGifSlurp);
7450DEF_IMGLIB_FN (DGifOpen);
7451DEF_IMGLIB_FN (DGifOpenFileName);
7452
7453static int
0855eb52 7454init_gif_functions (Lisp_Object libraries)
4ef0d4d0
KS
7455{
7456 HMODULE library;
7457
0855eb52 7458 if (!(library = w32_delayed_load (libraries, Qgif)))
4ef0d4d0
KS
7459 return 0;
7460
7461 LOAD_IMGLIB_FN (library, DGifCloseFile);
7462 LOAD_IMGLIB_FN (library, DGifSlurp);
7463 LOAD_IMGLIB_FN (library, DGifOpen);
7464 LOAD_IMGLIB_FN (library, DGifOpenFileName);
7465 return 1;
7466}
7467
7468#else
7469
7470#define fn_DGifCloseFile DGifCloseFile
7471#define fn_DGifSlurp DGifSlurp
7472#define fn_DGifOpen DGifOpen
7473#define fn_DGifOpenFileName DGifOpenFileName
7474
7475#endif /* HAVE_NTGUI */
7476
7477/* Reading a GIF image from memory
7478 Based on the PNG memory stuff to a certain extent. */
7479
7480typedef struct
7481{
7482 unsigned char *bytes;
7483 size_t len;
7484 int index;
7485}
7486gif_memory_source;
7487
7488/* Make the current memory source available to gif_read_from_memory.
7489 It's done this way because not all versions of libungif support
7490 a UserData field in the GifFileType structure. */
7491static gif_memory_source *current_gif_memory_src;
7492
7493static int
7494gif_read_from_memory (file, buf, len)
7495 GifFileType *file;
7496 GifByteType *buf;
7497 int len;
7498{
7499 gif_memory_source *src = current_gif_memory_src;
7500
7501 if (len > src->len - src->index)
7502 return -1;
7503
7504 bcopy (src->bytes + src->index, buf, len);
7505 src->index += len;
7506 return len;
7507}
7508
7509
7510/* Load GIF image IMG for use on frame F. Value is non-zero if
7511 successful. */
7512
aca946f3
GM
7513static int interlace_start[] = {0, 4, 2, 1};
7514static int interlace_increment[] = {8, 8, 4, 2};
7515
4ef0d4d0
KS
7516static int
7517gif_load (f, img)
7518 struct frame *f;
7519 struct image *img;
7520{
7521 Lisp_Object file, specified_file;
7522 Lisp_Object specified_data;
7523 int rc, width, height, x, y, i;
7524 XImagePtr ximg;
7525 ColorMapObject *gif_color_map;
7526 unsigned long pixel_colors[256];
7527 GifFileType *gif;
7528 struct gcpro gcpro1;
7529 Lisp_Object image;
6ac3c7bb 7530 int ino, image_height, image_width;
4ef0d4d0
KS
7531 gif_memory_source memsrc;
7532 unsigned char *raster;
7533
7534 specified_file = image_spec_value (img->spec, QCfile, NULL);
7535 specified_data = image_spec_value (img->spec, QCdata, NULL);
7536 file = Qnil;
7537 GCPRO1 (file);
7538
7539 if (NILP (specified_data))
7540 {
7541 file = x_find_image_file (specified_file);
7542 if (!STRINGP (file))
7543 {
7544 image_error ("Cannot find image file `%s'", specified_file, Qnil);
7545 UNGCPRO;
7546 return 0;
7547 }
7548
2e09fef1
EZ
7549 /* Open the GIF file. Casting return value avoids a GCC warning
7550 on W32. */
7551 gif = (GifFileType *)fn_DGifOpenFileName (SDATA (file));
4ef0d4d0
KS
7552 if (gif == NULL)
7553 {
7554 image_error ("Cannot open `%s'", file, Qnil);
7555 UNGCPRO;
7556 return 0;
7557 }
7558 }
7559 else
7560 {
7561 /* Read from memory! */
7562 current_gif_memory_src = &memsrc;
7563 memsrc.bytes = SDATA (specified_data);
7564 memsrc.len = SBYTES (specified_data);
7565 memsrc.index = 0;
7566
2e09fef1 7567 /* Casting return value avoids a GCC warning on W32. */
5fc9fdeb 7568 gif = (GifFileType *) fn_DGifOpen (&memsrc, gif_read_from_memory);
4ef0d4d0
KS
7569 if (!gif)
7570 {
7571 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
7572 UNGCPRO;
7573 return 0;
7574 }
7575 }
7576
f1f25b99
CY
7577 /* Before reading entire contents, check the declared image size. */
7578 if (!check_image_size (f, gif->SWidth, gif->SHeight))
7579 {
7580 image_error ("Invalid image size", Qnil, Qnil);
7581 fn_DGifCloseFile (gif);
7582 UNGCPRO;
7583 return 0;
7584 }
7585
4ef0d4d0
KS
7586 /* Read entire contents. */
7587 rc = fn_DGifSlurp (gif);
7588 if (rc == GIF_ERROR)
7589 {
7590 image_error ("Error reading `%s'", img->spec, Qnil);
7591 fn_DGifCloseFile (gif);
7592 UNGCPRO;
7593 return 0;
7594 }
7595
7596 image = image_spec_value (img->spec, QCindex, NULL);
7597 ino = INTEGERP (image) ? XFASTINT (image) : 0;
7598 if (ino >= gif->ImageCount)
7599 {
7600 image_error ("Invalid image number `%s' in image `%s'",
7601 image, img->spec);
7602 fn_DGifCloseFile (gif);
7603 UNGCPRO;
7604 return 0;
7605 }
7606
6ac3c7bb
KS
7607 img->corners[TOP_CORNER] = gif->SavedImages[ino].ImageDesc.Top;
7608 img->corners[LEFT_CORNER] = gif->SavedImages[ino].ImageDesc.Left;
0f4aca46 7609 image_height = gif->SavedImages[ino].ImageDesc.Height;
6ac3c7bb
KS
7610 img->corners[BOT_CORNER] = img->corners[TOP_CORNER] + image_height;
7611 image_width = gif->SavedImages[ino].ImageDesc.Width;
7612 img->corners[RIGHT_CORNER] = img->corners[LEFT_CORNER] + image_width;
0f4aca46
KS
7613
7614 width = img->width = max (gif->SWidth,
7615 max (gif->Image.Left + gif->Image.Width,
6ac3c7bb 7616 img->corners[RIGHT_CORNER]));
0f4aca46
KS
7617 height = img->height = max (gif->SHeight,
7618 max (gif->Image.Top + gif->Image.Height,
6ac3c7bb 7619 img->corners[BOT_CORNER]));
4ef0d4d0 7620
f1f25b99
CY
7621 if (!check_image_size (f, width, height))
7622 {
7623 image_error ("Invalid image size", Qnil, Qnil);
7624 fn_DGifCloseFile (gif);
7625 UNGCPRO;
7626 return 0;
7627 }
7628
4ef0d4d0
KS
7629 /* Create the X image and pixmap. */
7630 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
7631 {
7632 fn_DGifCloseFile (gif);
7633 UNGCPRO;
7634 return 0;
7635 }
7636
7637 /* Allocate colors. */
7638 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
7639 if (!gif_color_map)
7640 gif_color_map = gif->SColorMap;
7641 init_color_table ();
7642 bzero (pixel_colors, sizeof pixel_colors);
7643
1ab2cd43
TTN
7644 if (gif_color_map)
7645 for (i = 0; i < gif_color_map->ColorCount; ++i)
7646 {
7647 int r = gif_color_map->Colors[i].Red << 8;
7648 int g = gif_color_map->Colors[i].Green << 8;
7649 int b = gif_color_map->Colors[i].Blue << 8;
7650 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
7651 }
4ef0d4d0
KS
7652
7653#ifdef COLOR_TABLE_SUPPORT
7654 img->colors = colors_in_color_table (&img->ncolors);
7655 free_color_table ();
7656#endif /* COLOR_TABLE_SUPPORT */
7657
7658 /* Clear the part of the screen image that are not covered by
7659 the image from the GIF file. Full animated GIF support
7660 requires more than can be done here (see the gif89 spec,
7661 disposal methods). Let's simply assume that the part
7662 not covered by a sub-image is in the frame's background color. */
6ac3c7bb 7663 for (y = 0; y < img->corners[TOP_CORNER]; ++y)
4ef0d4d0
KS
7664 for (x = 0; x < width; ++x)
7665 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
7666
6ac3c7bb 7667 for (y = img->corners[BOT_CORNER]; y < height; ++y)
4ef0d4d0
KS
7668 for (x = 0; x < width; ++x)
7669 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
7670
6ac3c7bb 7671 for (y = img->corners[TOP_CORNER]; y < img->corners[BOT_CORNER]; ++y)
4ef0d4d0 7672 {
6ac3c7bb 7673 for (x = 0; x < img->corners[LEFT_CORNER]; ++x)
4ef0d4d0 7674 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
6ac3c7bb 7675 for (x = img->corners[RIGHT_CORNER]; x < width; ++x)
4ef0d4d0
KS
7676 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
7677 }
7678
7679 /* Read the GIF image into the X image. We use a local variable
7680 `raster' here because RasterBits below is a char *, and invites
7681 problems with bytes >= 0x80. */
7682 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
7683
7684 if (gif->SavedImages[ino].ImageDesc.Interlace)
7685 {
4ef0d4d0
KS
7686 int pass;
7687 int row = interlace_start[0];
7688
7689 pass = 0;
7690
7691 for (y = 0; y < image_height; y++)
7692 {
7693 if (row >= image_height)
7694 {
7695 row = interlace_start[++pass];
7696 while (row >= image_height)
7697 row = interlace_start[++pass];
7698 }
7699
7700 for (x = 0; x < image_width; x++)
7701 {
7702 int i = raster[(y * image_width) + x];
6ac3c7bb
KS
7703 XPutPixel (ximg, x + img->corners[LEFT_CORNER],
7704 row + img->corners[TOP_CORNER], pixel_colors[i]);
4ef0d4d0
KS
7705 }
7706
7707 row += interlace_increment[pass];
7708 }
7709 }
7710 else
7711 {
7712 for (y = 0; y < image_height; ++y)
7713 for (x = 0; x < image_width; ++x)
7714 {
7715 int i = raster[y * image_width + x];
6ac3c7bb
KS
7716 XPutPixel (ximg, x + img->corners[LEFT_CORNER],
7717 y + img->corners[TOP_CORNER], pixel_colors[i]);
4ef0d4d0
KS
7718 }
7719 }
7720
6ac3c7bb
KS
7721 /* Save GIF image extension data for `image-extension-data'.
7722 Format is (count IMAGES FUNCTION "BYTES" ...). */
7723 img->data.lisp_val = Qnil;
7724 if (gif->SavedImages[ino].ExtensionBlockCount > 0)
7725 {
7726 ExtensionBlock *ext = gif->SavedImages[ino].ExtensionBlocks;
7727 for (i = 0; i < gif->SavedImages[ino].ExtensionBlockCount; i++, ext++)
7728 /* Append (... FUNCTION "BYTES") */
7729 img->data.lisp_val = Fcons (make_unibyte_string (ext->Bytes, ext->ByteCount),
7730 Fcons (make_number (ext->Function),
7731 img->data.lisp_val));
7732 img->data.lisp_val = Fnreverse (img->data.lisp_val);
7733 }
7734 if (gif->ImageCount > 1)
7735 img->data.lisp_val = Fcons (Qcount,
7736 Fcons (make_number (gif->ImageCount),
7737 img->data.lisp_val));
7738
4ef0d4d0
KS
7739 fn_DGifCloseFile (gif);
7740
7741 /* Maybe fill in the background field while we have ximg handy. */
7742 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
2e09fef1
EZ
7743 /* Casting avoids a GCC warning. */
7744 IMAGE_BACKGROUND (img, f, (XImagePtr_or_DC)ximg);
4ef0d4d0
KS
7745
7746 /* Put the image into the pixmap, then free the X image and its buffer. */
7747 x_put_x_image (f, ximg, img->pixmap, width, height);
7748 x_destroy_x_image (ximg);
7749
7750 UNGCPRO;
7751 return 1;
7752}
7753
2e09fef1 7754#else /* !HAVE_GIF */
4ef0d4d0 7755
edfda783
AR
7756#ifdef HAVE_NS
7757static int
7758gif_load (struct frame *f, struct image *img)
7759{
7760 return ns_load_image(f, img,
7761 image_spec_value (img->spec, QCfile, NULL),
7762 image_spec_value (img->spec, QCdata, NULL));
7763}
7764#endif /* HAVE_NS */
7765
4ef0d4d0
KS
7766#endif /* HAVE_GIF */
7767
7768
7769\f
4ab27a43
GM
7770/***********************************************************************
7771 SVG
7772 ***********************************************************************/
7773
7774#if defined (HAVE_RSVG)
7775
7776/* Function prototypes. */
7777
7778static int svg_image_p P_ ((Lisp_Object object));
7779static int svg_load P_ ((struct frame *f, struct image *img));
7780
7781static int svg_load_image P_ ((struct frame *, struct image *,
7782 unsigned char *, unsigned int));
7783
7784/* The symbol `svg' identifying images of this type. */
7785
7786Lisp_Object Qsvg;
7787
7788/* Indices of image specification fields in svg_format, below. */
7789
7790enum svg_keyword_index
7791{
7792 SVG_TYPE,
7793 SVG_DATA,
7794 SVG_FILE,
7795 SVG_ASCENT,
7796 SVG_MARGIN,
7797 SVG_RELIEF,
7798 SVG_ALGORITHM,
7799 SVG_HEURISTIC_MASK,
7800 SVG_MASK,
7801 SVG_BACKGROUND,
7802 SVG_LAST
7803};
7804
7805/* Vector of image_keyword structures describing the format
7806 of valid user-defined image specifications. */
7807
7808static struct image_keyword svg_format[SVG_LAST] =
7809{
7810 {":type", IMAGE_SYMBOL_VALUE, 1},
7811 {":data", IMAGE_STRING_VALUE, 0},
7812 {":file", IMAGE_STRING_VALUE, 0},
7813 {":ascent", IMAGE_ASCENT_VALUE, 0},
7814 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
7815 {":relief", IMAGE_INTEGER_VALUE, 0},
7816 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7817 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7818 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7819 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
7820};
7821
7822/* Structure describing the image type `svg'. Its the same type of
7823 structure defined for all image formats, handled by emacs image
7824 functions. See struct image_type in dispextern.h. */
7825
7826static struct image_type svg_type =
7827{
7828 /* An identifier showing that this is an image structure for the SVG format. */
7829 &Qsvg,
7830 /* Handle to a function that can be used to identify a SVG file. */
7831 svg_image_p,
7832 /* Handle to function used to load a SVG file. */
7833 svg_load,
7834 /* Handle to function to free sresources for SVG. */
7835 x_clear_image,
7836 /* An internal field to link to the next image type in a list of
7837 image types, will be filled in when registering the format. */
c21e6151 7838 NULL
4ab27a43
GM
7839};
7840
7841
7842/* Return non-zero if OBJECT is a valid SVG image specification. Do
7843 this by calling parse_image_spec and supplying the keywords that
7844 identify the SVG format. */
7845
7846static int
7847svg_image_p (object)
7848 Lisp_Object object;
7849{
7850 struct image_keyword fmt[SVG_LAST];
7851 bcopy (svg_format, fmt, sizeof fmt);
7852
7853 if (!parse_image_spec (object, fmt, SVG_LAST, Qsvg))
7854 return 0;
7855
7856 /* Must specify either the :data or :file keyword. */
7857 return fmt[SVG_FILE].count + fmt[SVG_DATA].count == 1;
7858}
7859
7860#include <librsvg/rsvg.h>
7861
5fc9fdeb
JR
7862#ifdef HAVE_NTGUI
7863
7864/* SVG library functions. */
7865DEF_IMGLIB_FN (rsvg_handle_new);
e025c9c2 7866DEF_IMGLIB_FN (rsvg_handle_get_dimensions);
5fc9fdeb
JR
7867DEF_IMGLIB_FN (rsvg_handle_write);
7868DEF_IMGLIB_FN (rsvg_handle_close);
7869DEF_IMGLIB_FN (rsvg_handle_get_pixbuf);
7870DEF_IMGLIB_FN (rsvg_handle_free);
7871
7872DEF_IMGLIB_FN (gdk_pixbuf_get_width);
7873DEF_IMGLIB_FN (gdk_pixbuf_get_height);
7874DEF_IMGLIB_FN (gdk_pixbuf_get_pixels);
7875DEF_IMGLIB_FN (gdk_pixbuf_get_rowstride);
7876DEF_IMGLIB_FN (gdk_pixbuf_get_colorspace);
7877DEF_IMGLIB_FN (gdk_pixbuf_get_n_channels);
7878DEF_IMGLIB_FN (gdk_pixbuf_get_has_alpha);
7879DEF_IMGLIB_FN (gdk_pixbuf_get_bits_per_sample);
7880
7881DEF_IMGLIB_FN (g_type_init);
7882DEF_IMGLIB_FN (g_object_unref);
7883DEF_IMGLIB_FN (g_error_free);
7884
df23bf08 7885Lisp_Object Qgdk_pixbuf, Qglib, Qgobject;
5fc9fdeb
JR
7886
7887static int
7888init_svg_functions (Lisp_Object libraries)
7889{
df23bf08 7890 HMODULE library, gdklib, glib, gobject;
5fc9fdeb
JR
7891
7892 if (!(glib = w32_delayed_load (libraries, Qglib))
df23bf08 7893 || !(gobject = w32_delayed_load (libraries, Qgobject))
5fc9fdeb
JR
7894 || !(gdklib = w32_delayed_load (libraries, Qgdk_pixbuf))
7895 || !(library = w32_delayed_load (libraries, Qsvg)))
7896 return 0;
7897
7898 LOAD_IMGLIB_FN (library, rsvg_handle_new);
e025c9c2 7899 LOAD_IMGLIB_FN (library, rsvg_handle_get_dimensions);
5fc9fdeb
JR
7900 LOAD_IMGLIB_FN (library, rsvg_handle_write);
7901 LOAD_IMGLIB_FN (library, rsvg_handle_close);
7902 LOAD_IMGLIB_FN (library, rsvg_handle_get_pixbuf);
7903 LOAD_IMGLIB_FN (library, rsvg_handle_free);
7904
7905 LOAD_IMGLIB_FN (gdklib, gdk_pixbuf_get_width);
7906 LOAD_IMGLIB_FN (gdklib, gdk_pixbuf_get_height);
7907 LOAD_IMGLIB_FN (gdklib, gdk_pixbuf_get_pixels);
7908 LOAD_IMGLIB_FN (gdklib, gdk_pixbuf_get_rowstride);
7909 LOAD_IMGLIB_FN (gdklib, gdk_pixbuf_get_colorspace);
7910 LOAD_IMGLIB_FN (gdklib, gdk_pixbuf_get_n_channels);
7911 LOAD_IMGLIB_FN (gdklib, gdk_pixbuf_get_has_alpha);
7912 LOAD_IMGLIB_FN (gdklib, gdk_pixbuf_get_bits_per_sample);
7913
df23bf08
JR
7914 LOAD_IMGLIB_FN (gobject, g_type_init);
7915 LOAD_IMGLIB_FN (gobject, g_object_unref);
5fc9fdeb 7916 LOAD_IMGLIB_FN (glib, g_error_free);
df23bf08 7917
5fc9fdeb
JR
7918 return 1;
7919}
4ab27a43 7920
5fc9fdeb
JR
7921#else
7922/* The following aliases for library functions allow dynamic loading
7923 to be used on some platforms. */
4ab27a43 7924#define fn_rsvg_handle_new rsvg_handle_new
e025c9c2 7925#define fn_rsvg_handle_get_dimensions rsvg_handle_get_dimensions
4ab27a43
GM
7926#define fn_rsvg_handle_write rsvg_handle_write
7927#define fn_rsvg_handle_close rsvg_handle_close
7928#define fn_rsvg_handle_get_pixbuf rsvg_handle_get_pixbuf
7929#define fn_rsvg_handle_free rsvg_handle_free
7930
5fc9fdeb
JR
7931#define fn_gdk_pixbuf_get_width gdk_pixbuf_get_width
7932#define fn_gdk_pixbuf_get_height gdk_pixbuf_get_height
7933#define fn_gdk_pixbuf_get_pixels gdk_pixbuf_get_pixels
7934#define fn_gdk_pixbuf_get_rowstride gdk_pixbuf_get_rowstride
7935#define fn_gdk_pixbuf_get_colorspace gdk_pixbuf_get_colorspace
7936#define fn_gdk_pixbuf_get_n_channels gdk_pixbuf_get_n_channels
7937#define fn_gdk_pixbuf_get_has_alpha gdk_pixbuf_get_has_alpha
4ab27a43
GM
7938#define fn_gdk_pixbuf_get_bits_per_sample gdk_pixbuf_get_bits_per_sample
7939
5fc9fdeb
JR
7940#define fn_g_type_init g_type_init
7941#define fn_g_object_unref g_object_unref
7942#define fn_g_error_free g_error_free
7943#endif /* !HAVE_NTGUI */
4ab27a43
GM
7944
7945/* Load SVG image IMG for use on frame F. Value is non-zero if
7946 successful. this function will go into the svg_type structure, and
7947 the prototype thus needs to be compatible with that structure. */
7948
7949static int
7950svg_load (f, img)
7951 struct frame *f;
7952 struct image *img;
7953{
7954 int success_p = 0;
7955 Lisp_Object file_name;
7956
7957 /* If IMG->spec specifies a file name, create a non-file spec from it. */
7958 file_name = image_spec_value (img->spec, QCfile, NULL);
7959 if (STRINGP (file_name))
7960 {
7961 Lisp_Object file;
7962 unsigned char *contents;
7963 int size;
7964 struct gcpro gcpro1;
7965
7966 file = x_find_image_file (file_name);
7967 GCPRO1 (file);
7968 if (!STRINGP (file))
c21e6151
YM
7969 {
7970 image_error ("Cannot find image file `%s'", file_name, Qnil);
7971 UNGCPRO;
7972 return 0;
7973 }
7974
4ab27a43
GM
7975 /* Read the entire file into memory. */
7976 contents = slurp_file (SDATA (file), &size);
7977 if (contents == NULL)
c21e6151
YM
7978 {
7979 image_error ("Error loading SVG image `%s'", img->spec, Qnil);
7980 UNGCPRO;
7981 return 0;
7982 }
4ab27a43 7983 /* If the file was slurped into memory properly, parse it. */
c21e6151 7984 success_p = svg_load_image (f, img, contents, size);
4ab27a43
GM
7985 xfree (contents);
7986 UNGCPRO;
7987 }
7988 /* Else its not a file, its a lisp object. Load the image from a
7989 lisp object rather than a file. */
7990 else
7991 {
7992 Lisp_Object data;
7993
7994 data = image_spec_value (img->spec, QCdata, NULL);
7995 success_p = svg_load_image (f, img, SDATA (data), SBYTES (data));
7996 }
7997
7998 return success_p;
7999}
8000
bbe6f2aa
JB
8001/* svg_load_image is a helper function for svg_load, which does the
8002 actual loading given contents and size, apart from frame and image
8003 structures, passed from svg_load.
4ab27a43 8004
bbe6f2aa 8005 Uses librsvg to do most of the image processing.
c21e6151 8006
bbe6f2aa 8007 Returns non-zero when successful. */
4ab27a43
GM
8008static int
8009svg_load_image (f, img, contents, size)
bbe6f2aa 8010 /* Pointer to emacs frame structure. */
4ab27a43
GM
8011 struct frame *f;
8012 /* Pointer to emacs image structure. */
8013 struct image *img;
8014 /* String containing the SVG XML data to be parsed. */
8015 unsigned char *contents;
8016 /* Size of data in bytes. */
8017 unsigned int size;
8018{
8019 RsvgHandle *rsvg_handle;
e025c9c2 8020 RsvgDimensionData dimension_data;
4ab27a43
GM
8021 GError *error = NULL;
8022 GdkPixbuf *pixbuf;
8023 int width;
8024 int height;
8025 const guint8 *pixels;
8026 int rowstride;
8027 XImagePtr ximg;
c21e6151 8028 Lisp_Object specified_bg;
4ab27a43
GM
8029 XColor background;
8030 int x;
8031 int y;
8032
8033 /* g_type_init is a glib function that must be called prior to using
8034 gnome type library functions. */
5fc9fdeb 8035 fn_g_type_init ();
4ab27a43 8036 /* Make a handle to a new rsvg object. */
8b7d0a16 8037 rsvg_handle = (RsvgHandle *) fn_rsvg_handle_new ();
4ab27a43
GM
8038
8039 /* Parse the contents argument and fill in the rsvg_handle. */
8040 fn_rsvg_handle_write (rsvg_handle, contents, size, &error);
e025c9c2 8041 if (error) goto rsvg_error;
4ab27a43
GM
8042
8043 /* The parsing is complete, rsvg_handle is ready to used, close it
8044 for further writes. */
8045 fn_rsvg_handle_close (rsvg_handle, &error);
e025c9c2
CY
8046 if (error) goto rsvg_error;
8047
8048 fn_rsvg_handle_get_dimensions (rsvg_handle, &dimension_data);
8049 if (! check_image_size (f, dimension_data.width, dimension_data.height))
4ab27a43 8050 goto rsvg_error;
b2996e57 8051
4ab27a43
GM
8052 /* We can now get a valid pixel buffer from the svg file, if all
8053 went ok. */
8b7d0a16 8054 pixbuf = (GdkPixbuf *) fn_rsvg_handle_get_pixbuf (rsvg_handle);
e025c9c2
CY
8055 if (!pixbuf) goto rsvg_error;
8056 fn_g_object_unref (rsvg_handle);
4ab27a43
GM
8057
8058 /* Extract some meta data from the svg handle. */
8059 width = fn_gdk_pixbuf_get_width (pixbuf);
8060 height = fn_gdk_pixbuf_get_height (pixbuf);
8b7d0a16 8061 pixels = (const guint8 *) fn_gdk_pixbuf_get_pixels (pixbuf);
4ab27a43
GM
8062 rowstride = fn_gdk_pixbuf_get_rowstride (pixbuf);
8063
8064 /* Validate the svg meta data. */
8065 eassert (fn_gdk_pixbuf_get_colorspace (pixbuf) == GDK_COLORSPACE_RGB);
8066 eassert (fn_gdk_pixbuf_get_n_channels (pixbuf) == 4);
8067 eassert (fn_gdk_pixbuf_get_has_alpha (pixbuf));
8068 eassert (fn_gdk_pixbuf_get_bits_per_sample (pixbuf) == 8);
8069
8070 /* Try to create a x pixmap to hold the svg pixmap. */
c21e6151
YM
8071 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
8072 {
5fc9fdeb 8073 fn_g_object_unref (pixbuf);
c21e6151
YM
8074 return 0;
8075 }
4ab27a43
GM
8076
8077 init_color_table ();
8078
c21e6151
YM
8079 /* Handle alpha channel by combining the image with a background
8080 color. */
8081 specified_bg = image_spec_value (img->spec, QCbackground, NULL);
8082 if (STRINGP (specified_bg)
8083 && x_defined_color (f, SDATA (specified_bg), &background, 0))
8084 {
8085 background.red >>= 8;
8086 background.green >>= 8;
8087 background.blue >>= 8;
8088 }
8089 else
8090 {
c21e6151
YM
8091 background.pixel = FRAME_BACKGROUND_PIXEL (f);
8092 x_query_color (f, &background);
8093
8094 /* SVG pixmaps specify transparency in the last byte, so right
3046a84b 8095 shift 8 bits to get rid of it, since emacs doesn't support
c21e6151
YM
8096 transparency. */
8097 background.red >>= 8;
8098 background.green >>= 8;
8099 background.blue >>= 8;
c21e6151 8100 }
4ab27a43
GM
8101
8102 /* This loop handles opacity values, since Emacs assumes
8103 non-transparent images. Each pixel must be "flattened" by
bbe6f2aa
JB
8104 calculating the resulting color, given the transparency of the
8105 pixel, and the image background color. */
4ab27a43
GM
8106 for (y = 0; y < height; ++y)
8107 {
8108 for (x = 0; x < width; ++x)
8109 {
8110 unsigned red;
8111 unsigned green;
8112 unsigned blue;
8113 unsigned opacity;
8114
8115 red = *pixels++;
8116 green = *pixels++;
8117 blue = *pixels++;
8118 opacity = *pixels++;
8119
8120 red = ((red * opacity)
8121 + (background.red * ((1 << 8) - opacity)));
8122 green = ((green * opacity)
8123 + (background.green * ((1 << 8) - opacity)));
8124 blue = ((blue * opacity)
8125 + (background.blue * ((1 << 8) - opacity)));
8126
8127 XPutPixel (ximg, x, y, lookup_rgb_color (f, red, green, blue));
8128 }
8129
8130 pixels += rowstride - 4 * width;
8131 }
8132
8133#ifdef COLOR_TABLE_SUPPORT
8134 /* Remember colors allocated for this image. */
8135 img->colors = colors_in_color_table (&img->ncolors);
8136 free_color_table ();
8137#endif /* COLOR_TABLE_SUPPORT */
8138
5fc9fdeb 8139 fn_g_object_unref (pixbuf);
4ab27a43 8140
c21e6151
YM
8141 img->width = width;
8142 img->height = height;
8143
8144 /* Maybe fill in the background field while we have ximg handy.
8145 Casting avoids a GCC warning. */
8146 IMAGE_BACKGROUND (img, f, (XImagePtr_or_DC)ximg);
8147
4ab27a43
GM
8148 /* Put the image into the pixmap, then free the X image and its
8149 buffer. */
8150 x_put_x_image (f, ximg, img->pixmap, width, height);
8151 x_destroy_x_image (ximg);
8152
4ab27a43
GM
8153 return 1;
8154
8155 rsvg_error:
e025c9c2 8156 fn_g_object_unref (rsvg_handle);
4ab27a43
GM
8157 /* FIXME: Use error->message so the user knows what is the actual
8158 problem with the image. */
8159 image_error ("Error parsing SVG image `%s'", img->spec, Qnil);
5fc9fdeb 8160 fn_g_error_free (error);
4ab27a43
GM
8161 return 0;
8162}
8163
8164#endif /* defined (HAVE_RSVG) */
8165
8166
8167
4ef0d4d0
KS
8168\f
8169/***********************************************************************
8170 Ghostscript
8171 ***********************************************************************/
8172
8173#ifdef HAVE_X_WINDOWS
8174#define HAVE_GHOSTSCRIPT 1
8175#endif /* HAVE_X_WINDOWS */
8176
8177/* The symbol `postscript' identifying images of this type. */
8178
8179Lisp_Object Qpostscript;
8180
8181#ifdef HAVE_GHOSTSCRIPT
8182
8183static int gs_image_p P_ ((Lisp_Object object));
8184static int gs_load P_ ((struct frame *f, struct image *img));
8185static void gs_clear_image P_ ((struct frame *f, struct image *img));
8186
8187/* Keyword symbols. */
8188
8189Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
8190
8191/* Indices of image specification fields in gs_format, below. */
8192
8193enum gs_keyword_index
8194{
8195 GS_TYPE,
8196 GS_PT_WIDTH,
8197 GS_PT_HEIGHT,
8198 GS_FILE,
8199 GS_LOADER,
8200 GS_BOUNDING_BOX,
8201 GS_ASCENT,
8202 GS_MARGIN,
8203 GS_RELIEF,
8204 GS_ALGORITHM,
8205 GS_HEURISTIC_MASK,
8206 GS_MASK,
8207 GS_BACKGROUND,
8208 GS_LAST
8209};
8210
8211/* Vector of image_keyword structures describing the format
8212 of valid user-defined image specifications. */
8213
8214static struct image_keyword gs_format[GS_LAST] =
8215{
8216 {":type", IMAGE_SYMBOL_VALUE, 1},
8217 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
8218 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
8219 {":file", IMAGE_STRING_VALUE, 1},
8220 {":loader", IMAGE_FUNCTION_VALUE, 0},
8221 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
8222 {":ascent", IMAGE_ASCENT_VALUE, 0},
8223 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
8224 {":relief", IMAGE_INTEGER_VALUE, 0},
8225 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8226 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8227 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8228 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
8229};
8230
8231/* Structure describing the image type `ghostscript'. */
8232
8233static struct image_type gs_type =
8234{
8235 &Qpostscript,
8236 gs_image_p,
8237 gs_load,
8238 gs_clear_image,
8239 NULL
8240};
8241
8242
8243/* Free X resources of Ghostscript image IMG which is used on frame F. */
8244
8245static void
8246gs_clear_image (f, img)
8247 struct frame *f;
8248 struct image *img;
8249{
8250 /* IMG->data.ptr_val may contain a recorded colormap. */
8251 xfree (img->data.ptr_val);
8252 x_clear_image (f, img);
8253}
8254
8255
8256/* Return non-zero if OBJECT is a valid Ghostscript image
8257 specification. */
8258
8259static int
8260gs_image_p (object)
8261 Lisp_Object object;
8262{
8263 struct image_keyword fmt[GS_LAST];
8264 Lisp_Object tem;
8265 int i;
8266
8267 bcopy (gs_format, fmt, sizeof fmt);
8268
8269 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript))
8270 return 0;
8271
8272 /* Bounding box must be a list or vector containing 4 integers. */
8273 tem = fmt[GS_BOUNDING_BOX].value;
8274 if (CONSP (tem))
8275 {
8276 for (i = 0; i < 4; ++i, tem = XCDR (tem))
8277 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
8278 return 0;
8279 if (!NILP (tem))
8280 return 0;
8281 }
8282 else if (VECTORP (tem))
8283 {
8284 if (XVECTOR (tem)->size != 4)
8285 return 0;
8286 for (i = 0; i < 4; ++i)
8287 if (!INTEGERP (XVECTOR (tem)->contents[i]))
8288 return 0;
8289 }
8290 else
8291 return 0;
8292
8293 return 1;
8294}
8295
8296
8297/* Load Ghostscript image IMG for use on frame F. Value is non-zero
8298 if successful. */
8299
8300static int
8301gs_load (f, img)
8302 struct frame *f;
8303 struct image *img;
8304{
8305 char buffer[100];
8306 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
8307 struct gcpro gcpro1, gcpro2;
8308 Lisp_Object frame;
8309 double in_width, in_height;
8310 Lisp_Object pixel_colors = Qnil;
8311
8312 /* Compute pixel size of pixmap needed from the given size in the
8313 image specification. Sizes in the specification are in pt. 1 pt
8314 = 1/72 in, xdpi and ydpi are stored in the frame's X display
8315 info. */
8316 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
8317 in_width = XFASTINT (pt_width) / 72.0;
8318 img->width = in_width * FRAME_X_DISPLAY_INFO (f)->resx;
8319 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
8320 in_height = XFASTINT (pt_height) / 72.0;
8321 img->height = in_height * FRAME_X_DISPLAY_INFO (f)->resy;
8322
f1f25b99
CY
8323 if (!check_image_size (f, img->width, img->height))
8324 {
8325 image_error ("Invalid image size", Qnil, Qnil);
8326 return 0;
8327 }
8328
4ef0d4d0
KS
8329 /* Create the pixmap. */
8330 xassert (img->pixmap == NO_PIXMAP);
8331
8332 /* Only W32 version did BLOCK_INPUT here. ++kfs */
8333 BLOCK_INPUT;
8334 img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8335 img->width, img->height,
8336 DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
8337 UNBLOCK_INPUT;
8338
8339 if (!img->pixmap)
8340 {
8341 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
8342 return 0;
8343 }
8344
8345 /* Call the loader to fill the pixmap. It returns a process object
8346 if successful. We do not record_unwind_protect here because
8347 other places in redisplay like calling window scroll functions
8348 don't either. Let the Lisp loader use `unwind-protect' instead. */
8349 GCPRO2 (window_and_pixmap_id, pixel_colors);
8350
8351 sprintf (buffer, "%lu %lu",
8352 (unsigned long) FRAME_X_WINDOW (f),
8353 (unsigned long) img->pixmap);
8354 window_and_pixmap_id = build_string (buffer);
8355
8356 sprintf (buffer, "%lu %lu",
8357 FRAME_FOREGROUND_PIXEL (f),
8358 FRAME_BACKGROUND_PIXEL (f));
8359 pixel_colors = build_string (buffer);
8360
8361 XSETFRAME (frame, f);
8362 loader = image_spec_value (img->spec, QCloader, NULL);
8363 if (NILP (loader))
8364 loader = intern ("gs-load-image");
8365
8366 img->data.lisp_val = call6 (loader, frame, img->spec,
8367 make_number (img->width),
8368 make_number (img->height),
8369 window_and_pixmap_id,
8370 pixel_colors);
8371 UNGCPRO;
8372 return PROCESSP (img->data.lisp_val);
8373}
8374
8375
8376/* Kill the Ghostscript process that was started to fill PIXMAP on
8377 frame F. Called from XTread_socket when receiving an event
8378 telling Emacs that Ghostscript has finished drawing. */
8379
8380void
8381x_kill_gs_process (pixmap, f)
8382 Pixmap pixmap;
8383 struct frame *f;
8384{
354884c4 8385 struct image_cache *c = FRAME_IMAGE_CACHE (f);
4ef0d4d0
KS
8386 int class, i;
8387 struct image *img;
8388
8389 /* Find the image containing PIXMAP. */
8390 for (i = 0; i < c->used; ++i)
8391 if (c->images[i]->pixmap == pixmap)
8392 break;
8393
8394 /* Should someone in between have cleared the image cache, for
8395 instance, give up. */
8396 if (i == c->used)
8397 return;
8398
8399 /* Kill the GS process. We should have found PIXMAP in the image
8400 cache and its image should contain a process object. */
8401 img = c->images[i];
8402 xassert (PROCESSP (img->data.lisp_val));
8403 Fkill_process (img->data.lisp_val, Qnil);
8404 img->data.lisp_val = Qnil;
8405
8406#if defined (HAVE_X_WINDOWS)
8407
8408 /* On displays with a mutable colormap, figure out the colors
8409 allocated for the image by looking at the pixels of an XImage for
8410 img->pixmap. */
8411 class = FRAME_X_VISUAL (f)->class;
8412 if (class != StaticColor && class != StaticGray && class != TrueColor)
8413 {
8414 XImagePtr ximg;
8415
8416 BLOCK_INPUT;
8417
8418 /* Try to get an XImage for img->pixmep. */
8419 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
8420 0, 0, img->width, img->height, ~0, ZPixmap);
8421 if (ximg)
8422 {
8423 int x, y;
8424
8425 /* Initialize the color table. */
8426 init_color_table ();
8427
8428 /* For each pixel of the image, look its color up in the
8429 color table. After having done so, the color table will
8430 contain an entry for each color used by the image. */
8431 for (y = 0; y < img->height; ++y)
8432 for (x = 0; x < img->width; ++x)
8433 {
8434 unsigned long pixel = XGetPixel (ximg, x, y);
8435 lookup_pixel_color (f, pixel);
8436 }
8437
8438 /* Record colors in the image. Free color table and XImage. */
8439#ifdef COLOR_TABLE_SUPPORT
8440 img->colors = colors_in_color_table (&img->ncolors);
8441 free_color_table ();
8442#endif
8443 XDestroyImage (ximg);
8444
8445#if 0 /* This doesn't seem to be the case. If we free the colors
8446 here, we get a BadAccess later in x_clear_image when
8447 freeing the colors. */
8448 /* We have allocated colors once, but Ghostscript has also
8449 allocated colors on behalf of us. So, to get the
8450 reference counts right, free them once. */
8451 if (img->ncolors)
8452 x_free_colors (f, img->colors, img->ncolors);
8453#endif
8454 }
8455 else
8456 image_error ("Cannot get X image of `%s'; colors will not be freed",
8457 img->spec, Qnil);
8458
8459 UNBLOCK_INPUT;
8460 }
8461#endif /* HAVE_X_WINDOWS */
8462
8463 /* Now that we have the pixmap, compute mask and transform the
8464 image if requested. */
8465 BLOCK_INPUT;
8466 postprocess_image (f, img);
8467 UNBLOCK_INPUT;
8468}
8469
8470#endif /* HAVE_GHOSTSCRIPT */
8471
8472\f
8473/***********************************************************************
8474 Tests
8475 ***********************************************************************/
8476
8477#if GLYPH_DEBUG
8478
8479DEFUN ("imagep", Fimagep, Simagep, 1, 1, 0,
8480 doc: /* Value is non-nil if SPEC is a valid image specification. */)
8481 (spec)
8482 Lisp_Object spec;
8483{
8484 return valid_image_p (spec) ? Qt : Qnil;
8485}
8486
8487
8488DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0, "")
8489 (spec)
8490 Lisp_Object spec;
8491{
8492 int id = -1;
8493
8494 if (valid_image_p (spec))
8495 id = lookup_image (SELECTED_FRAME (), spec);
8496
8497 debug_print (spec);
8498 return make_number (id);
8499}
8500
8501#endif /* GLYPH_DEBUG != 0 */
8502
8503
8504/***********************************************************************
8505 Initialization
8506 ***********************************************************************/
8507
0855eb52
JB
8508#ifdef HAVE_NTGUI
8509/* Image types that rely on external libraries are loaded dynamically
8510 if the library is available. */
adac86db 8511#define CHECK_LIB_AVAILABLE(image_type, init_lib_fn, libraries) \
0855eb52
JB
8512 define_image_type (image_type, init_lib_fn (libraries))
8513#else
adac86db 8514#define CHECK_LIB_AVAILABLE(image_type, init_lib_fn, libraries) \
e0e30823 8515 define_image_type (image_type, 1)
0855eb52
JB
8516#endif /* HAVE_NTGUI */
8517
8518DEFUN ("init-image-library", Finit_image_library, Sinit_image_library, 2, 2, 0,
8519 doc: /* Initialize image library implementing image type TYPE.
8520Return non-nil if TYPE is a supported image type.
8521
8522Image types pbm and xbm are prebuilt; other types are loaded here.
8523Libraries to load are specified in alist LIBRARIES (usually, the value
adac86db 8524of `image-library-alist', which see). */)
0855eb52 8525 (type, libraries)
adac86db 8526 Lisp_Object type, libraries;
0855eb52
JB
8527{
8528 Lisp_Object tested;
8529
8530 /* Don't try to reload the library. */
8531 tested = Fassq (type, Vimage_type_cache);
8532 if (CONSP (tested))
8533 return XCDR (tested);
8534
9e2a2647 8535#if defined (HAVE_XPM) || defined (HAVE_NS)
0855eb52 8536 if (EQ (type, Qxpm))
adac86db 8537 return CHECK_LIB_AVAILABLE (&xpm_type, init_xpm_functions, libraries);
0855eb52
JB
8538#endif
8539
9e2a2647 8540#if defined (HAVE_JPEG) || defined (HAVE_NS)
0855eb52 8541 if (EQ (type, Qjpeg))
adac86db 8542 return CHECK_LIB_AVAILABLE (&jpeg_type, init_jpeg_functions, libraries);
0855eb52
JB
8543#endif
8544
9e2a2647 8545#if defined (HAVE_TIFF) || defined (HAVE_NS)
0855eb52 8546 if (EQ (type, Qtiff))
adac86db 8547 return CHECK_LIB_AVAILABLE (&tiff_type, init_tiff_functions, libraries);
0855eb52
JB
8548#endif
8549
9e2a2647 8550#if defined (HAVE_GIF) || defined (HAVE_NS)
0855eb52 8551 if (EQ (type, Qgif))
adac86db 8552 return CHECK_LIB_AVAILABLE (&gif_type, init_gif_functions, libraries);
0855eb52
JB
8553#endif
8554
9e2a2647 8555#if defined (HAVE_PNG) || defined (HAVE_NS)
0855eb52 8556 if (EQ (type, Qpng))
adac86db 8557 return CHECK_LIB_AVAILABLE (&png_type, init_png_functions, libraries);
0855eb52
JB
8558#endif
8559
4ab27a43
GM
8560#if defined (HAVE_RSVG)
8561 if (EQ (type, Qsvg))
8562 return CHECK_LIB_AVAILABLE (&svg_type, init_svg_functions, libraries);
8563#endif
c21e6151 8564
0855eb52
JB
8565#ifdef HAVE_GHOSTSCRIPT
8566 if (EQ (type, Qpostscript))
adac86db 8567 return CHECK_LIB_AVAILABLE (&gs_type, init_gs_functions, libraries);
0855eb52
JB
8568#endif
8569
8570 /* If the type is not recognized, avoid testing it ever again. */
adac86db 8571 CACHE_IMAGE_TYPE (type, Qnil);
0855eb52
JB
8572 return Qnil;
8573}
8574
4ef0d4d0
KS
8575void
8576syms_of_image ()
8577{
2a611c1a
JB
8578 extern Lisp_Object Qrisky_local_variable; /* Syms_of_xdisp has already run. */
8579
6e6fc3fd
RS
8580 /* Initialize this only once, since that's what we do with Vimage_types
8581 and they are supposed to be in sync. Initializing here gives correct
8582 operation on GNU/Linux of calling dump-emacs after loading some images. */
8583 image_types = NULL;
8584
0855eb52
JB
8585 /* Must be defined now becase we're going to update it below, while
8586 defining the supported image types. */
8587 DEFVAR_LISP ("image-types", &Vimage_types,
8588 doc: /* List of potentially supported image types.
bbe6f2aa 8589Each element of the list is a symbol for an image type, like 'jpeg or 'png.
0855eb52
JB
8590To check whether it is really supported, use `image-type-available-p'. */);
8591 Vimage_types = Qnil;
8592
2a611c1a
JB
8593 DEFVAR_LISP ("image-library-alist", &Vimage_library_alist,
8594 doc: /* Alist of image types vs external libraries needed to display them.
8595
8596Each element is a list (IMAGE-TYPE LIBRARY...), where the car is a symbol
8597representing a supported image type, and the rest are strings giving
8598alternate filenames for the corresponding external libraries.
8599
8600Emacs tries to load the libraries in the order they appear on the
8601list; if none is loaded, the running session of Emacs won't
8602support the image type. Types 'pbm and 'xbm don't need to be
3046a84b 8603listed; they are always supported. */);
2a611c1a
JB
8604 Vimage_library_alist = Qnil;
8605 Fput (intern ("image-library-alist"), Qrisky_local_variable, Qt);
8606
f1f25b99 8607 DEFVAR_LISP ("max-image-size", &Vmax_image_size,
7df4765a
KS
8608 doc: /* Maximum size of images.
8609Emacs will not load an image into memory if its pixel width or
8610pixel height exceeds this limit.
8611
8612If the value is an integer, it directly specifies the maximum
8613image height and width, measured in pixels. If it is a floating
8614point number, it specifies the maximum image height and width
8615as a ratio to the frame height and width. If the value is
8616non-numeric, there is no explicit limit on the size of images. */);
f1f25b99
CY
8617 Vmax_image_size = make_float (MAX_IMAGE_SIZE);
8618
0855eb52
JB
8619 Vimage_type_cache = Qnil;
8620 staticpro (&Vimage_type_cache);
8621
7c4e3a32
RS
8622 Qpbm = intern ("pbm");
8623 staticpro (&Qpbm);
5fc9fdeb 8624 ADD_IMAGE_TYPE (Qpbm);
7c4e3a32
RS
8625
8626 Qxbm = intern ("xbm");
8627 staticpro (&Qxbm);
5fc9fdeb 8628 ADD_IMAGE_TYPE (Qxbm);
7c4e3a32
RS
8629
8630 define_image_type (&xbm_type, 1);
8631 define_image_type (&pbm_type, 1);
8632
e047f448
SM
8633 Qcount = intern ("count");
8634 staticpro (&Qcount);
8635
4ef0d4d0
KS
8636 QCascent = intern (":ascent");
8637 staticpro (&QCascent);
8638 QCmargin = intern (":margin");
8639 staticpro (&QCmargin);
8640 QCrelief = intern (":relief");
8641 staticpro (&QCrelief);
8642 QCconversion = intern (":conversion");
8643 staticpro (&QCconversion);
8644 QCcolor_symbols = intern (":color-symbols");
8645 staticpro (&QCcolor_symbols);
8646 QCheuristic_mask = intern (":heuristic-mask");
8647 staticpro (&QCheuristic_mask);
8648 QCindex = intern (":index");
8649 staticpro (&QCindex);
8650 QCmatrix = intern (":matrix");
8651 staticpro (&QCmatrix);
8652 QCcolor_adjustment = intern (":color-adjustment");
8653 staticpro (&QCcolor_adjustment);
8654 QCmask = intern (":mask");
8655 staticpro (&QCmask);
8656
8657 Qlaplace = intern ("laplace");
8658 staticpro (&Qlaplace);
8659 Qemboss = intern ("emboss");
8660 staticpro (&Qemboss);
8661 Qedge_detection = intern ("edge-detection");
8662 staticpro (&Qedge_detection);
8663 Qheuristic = intern ("heuristic");
8664 staticpro (&Qheuristic);
4ef0d4d0
KS
8665
8666 Qpostscript = intern ("postscript");
8667 staticpro (&Qpostscript);
8668#ifdef HAVE_GHOSTSCRIPT
5fc9fdeb 8669 ADD_IMAGE_TYPE (Qpostscript);
4ef0d4d0
KS
8670 QCloader = intern (":loader");
8671 staticpro (&QCloader);
8672 QCbounding_box = intern (":bounding-box");
8673 staticpro (&QCbounding_box);
8674 QCpt_width = intern (":pt-width");
8675 staticpro (&QCpt_width);
8676 QCpt_height = intern (":pt-height");
8677 staticpro (&QCpt_height);
8678#endif /* HAVE_GHOSTSCRIPT */
8679
9e2a2647 8680#if defined (HAVE_XPM) || defined (HAVE_NS)
4ef0d4d0
KS
8681 Qxpm = intern ("xpm");
8682 staticpro (&Qxpm);
5fc9fdeb 8683 ADD_IMAGE_TYPE (Qxpm);
4ef0d4d0
KS
8684#endif
8685
9e2a2647 8686#if defined (HAVE_JPEG) || defined (HAVE_NS)
4ef0d4d0
KS
8687 Qjpeg = intern ("jpeg");
8688 staticpro (&Qjpeg);
5fc9fdeb 8689 ADD_IMAGE_TYPE (Qjpeg);
4ef0d4d0
KS
8690#endif
8691
9e2a2647 8692#if defined (HAVE_TIFF) || defined (HAVE_NS)
4ef0d4d0
KS
8693 Qtiff = intern ("tiff");
8694 staticpro (&Qtiff);
5fc9fdeb 8695 ADD_IMAGE_TYPE (Qtiff);
4ef0d4d0
KS
8696#endif
8697
9e2a2647 8698#if defined (HAVE_GIF) || defined (HAVE_NS)
4ef0d4d0
KS
8699 Qgif = intern ("gif");
8700 staticpro (&Qgif);
5fc9fdeb 8701 ADD_IMAGE_TYPE (Qgif);
4ef0d4d0
KS
8702#endif
8703
9e2a2647 8704#if defined (HAVE_PNG) || defined (HAVE_NS)
4ef0d4d0
KS
8705 Qpng = intern ("png");
8706 staticpro (&Qpng);
5fc9fdeb 8707 ADD_IMAGE_TYPE (Qpng);
4ef0d4d0
KS
8708#endif
8709
4ab27a43
GM
8710#if defined (HAVE_RSVG)
8711 Qsvg = intern ("svg");
8712 staticpro (&Qsvg);
5fc9fdeb
JR
8713 ADD_IMAGE_TYPE (Qsvg);
8714#ifdef HAVE_NTGUI
df23bf08 8715 /* Other libraries used directly by svg code. */
5fc9fdeb
JR
8716 Qgdk_pixbuf = intern ("gdk-pixbuf");
8717 staticpro (&Qgdk_pixbuf);
8718 Qglib = intern ("glib");
8719 staticpro (&Qglib);
df23bf08
JR
8720 Qgobject = intern ("gobject");
8721 staticpro (&Qgobject);
5fc9fdeb
JR
8722#endif /* HAVE_NTGUI */
8723#endif /* HAVE_RSVG */
4ab27a43 8724
0855eb52 8725 defsubr (&Sinit_image_library);
4ef0d4d0 8726 defsubr (&Sclear_image_cache);
483e7ae0 8727 defsubr (&Simage_refresh);
4ef0d4d0
KS
8728 defsubr (&Simage_size);
8729 defsubr (&Simage_mask_p);
6ac3c7bb 8730 defsubr (&Simage_extension_data);
4ef0d4d0
KS
8731
8732#if GLYPH_DEBUG
8733 defsubr (&Simagep);
8734 defsubr (&Slookup_image);
8735#endif
8736
8737 DEFVAR_BOOL ("cross-disabled-images", &cross_disabled_images,
8738 doc: /* Non-nil means always draw a cross over disabled images.
3046a84b 8739Disabled images are those having a `:conversion disabled' property.
4ef0d4d0
KS
8740A cross is always drawn on black & white displays. */);
8741 cross_disabled_images = 0;
8742
8743 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
8744 doc: /* List of directories to search for window system bitmap files. */);
8745 Vx_bitmap_file_path = decode_env_path ((char *) 0, PATH_BITMAPS);
8746
8747 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
8748 doc: /* Time after which cached images are removed from the cache.
8749When an image has not been displayed this many seconds, remove it
8750from the image cache. Value must be an integer or nil with nil
8751meaning don't clear the cache. */);
8752 Vimage_cache_eviction_delay = make_number (30 * 60);
8753}
8754
4ef0d4d0
KS
8755void
8756init_image ()
8757{
4ef0d4d0
KS
8758}
8759
1b9f8cec
MB
8760/* arch-tag: 123c2a5e-14a8-4c53-ab95-af47d7db49b9
8761 (do not change this comment) */