* net/browse-url.el (browse-url): Identify alist with "consp and
[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 *,
ce959360 2546 int *, int *, unsigned char **, int));
4ef0d4d0
KS
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
ce959360
CY
2937 CONTENTS looks like an in-memory XBM file. If INHIBIT_IMAGE_ERROR
2938 is non-zero, inhibit the call to image_error when the image size is
2939 invalid (the bitmap remains unread). */
4ef0d4d0
KS
2940
2941static int
ce959360 2942xbm_read_bitmap_data (f, contents, end, width, height, data, inhibit_image_error)
f1f25b99 2943 struct frame *f;
4ef0d4d0
KS
2944 unsigned char *contents, *end;
2945 int *width, *height;
2946 unsigned char **data;
ce959360 2947 int inhibit_image_error;
4ef0d4d0
KS
2948{
2949 unsigned char *s = contents;
2950 char buffer[BUFSIZ];
2951 int padding_p = 0;
2952 int v10 = 0;
2953 int bytes_per_line, i, nbytes;
2954 unsigned char *p;
2955 int value;
2956 int LA1;
2957
2958#define match() \
2959 LA1 = xbm_scan (&s, end, buffer, &value)
2960
2961#define expect(TOKEN) \
2962 if (LA1 != (TOKEN)) \
2963 goto failure; \
2964 else \
2965 match ()
2966
2967#define expect_ident(IDENT) \
2968 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
2969 match (); \
2970 else \
2971 goto failure
2972
2973 *width = *height = -1;
2974 if (data)
2975 *data = NULL;
2976 LA1 = xbm_scan (&s, end, buffer, &value);
2977
2978 /* Parse defines for width, height and hot-spots. */
2979 while (LA1 == '#')
2980 {
2981 match ();
2982 expect_ident ("define");
2983 expect (XBM_TK_IDENT);
2984
431feaf6 2985 if (LA1 == XBM_TK_NUMBER)
4ef0d4d0
KS
2986 {
2987 char *p = strrchr (buffer, '_');
2988 p = p ? p + 1 : buffer;
2989 if (strcmp (p, "width") == 0)
2990 *width = value;
2991 else if (strcmp (p, "height") == 0)
2992 *height = value;
2993 }
2994 expect (XBM_TK_NUMBER);
2995 }
2996
f1f25b99 2997 if (!check_image_size (f, *width, *height))
10ea2b82 2998 {
ce959360
CY
2999 if (!inhibit_image_error)
3000 image_error ("Invalid image size (see `max-image-size')", Qnil, Qnil);
10ea2b82
JR
3001 goto failure;
3002 }
4ef0d4d0
KS
3003 else if (data == NULL)
3004 goto success;
3005
3006 /* Parse bits. Must start with `static'. */
3007 expect_ident ("static");
3008 if (LA1 == XBM_TK_IDENT)
3009 {
3010 if (strcmp (buffer, "unsigned") == 0)
3011 {
3012 match ();
3013 expect_ident ("char");
3014 }
3015 else if (strcmp (buffer, "short") == 0)
3016 {
3017 match ();
3018 v10 = 1;
3019 if (*width % 16 && *width % 16 < 9)
3020 padding_p = 1;
3021 }
3022 else if (strcmp (buffer, "char") == 0)
3023 match ();
3024 else
3025 goto failure;
3026 }
3027 else
3028 goto failure;
3029
3030 expect (XBM_TK_IDENT);
3031 expect ('[');
3032 expect (']');
3033 expect ('=');
3034 expect ('{');
3035
3036 bytes_per_line = (*width + 7) / 8 + padding_p;
3037 nbytes = bytes_per_line * *height;
fa8459a3 3038 p = *data = (unsigned char *) xmalloc (nbytes);
4ef0d4d0
KS
3039
3040 if (v10)
3041 {
3042 for (i = 0; i < nbytes; i += 2)
3043 {
3044 int val = value;
3045 expect (XBM_TK_NUMBER);
3046
3047 *p++ = XBM_BIT_SHUFFLE (val);
3048 if (!padding_p || ((i + 2) % bytes_per_line))
3049 *p++ = XBM_BIT_SHUFFLE (value >> 8);
3050
3051 if (LA1 == ',' || LA1 == '}')
3052 match ();
3053 else
3054 goto failure;
3055 }
3056 }
3057 else
3058 {
3059 for (i = 0; i < nbytes; ++i)
3060 {
3061 int val = value;
3062 expect (XBM_TK_NUMBER);
3063
3064 *p++ = XBM_BIT_SHUFFLE (val);
3065
3066 if (LA1 == ',' || LA1 == '}')
3067 match ();
3068 else
3069 goto failure;
3070 }
3071 }
3072
3073 success:
3074 return 1;
3075
3076 failure:
3077
3078 if (data && *data)
3079 {
3080 xfree (*data);
3081 *data = NULL;
3082 }
3083 return 0;
3084
3085#undef match
3086#undef expect
3087#undef expect_ident
3088}
3089
3090
3091/* Load XBM image IMG which will be displayed on frame F from buffer
3092 CONTENTS. END is the end of the buffer. Value is non-zero if
3093 successful. */
3094
3095static int
3096xbm_load_image (f, img, contents, end)
3097 struct frame *f;
3098 struct image *img;
3099 unsigned char *contents, *end;
3100{
3101 int rc;
3102 unsigned char *data;
3103 int success_p = 0;
3104
ce959360
CY
3105 rc = xbm_read_bitmap_data (f, contents, end, &img->width, &img->height,
3106 &data, 0);
4ef0d4d0
KS
3107 if (rc)
3108 {
3109 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
3110 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
3111 int non_default_colors = 0;
3112 Lisp_Object value;
3113
3114 xassert (img->width > 0 && img->height > 0);
3115
3116 /* Get foreground and background colors, maybe allocate colors. */
3117 value = image_spec_value (img->spec, QCforeground, NULL);
3118 if (!NILP (value))
3119 {
3120 foreground = x_alloc_image_color (f, img, value, foreground);
3121 non_default_colors = 1;
3122 }
3123 value = image_spec_value (img->spec, QCbackground, NULL);
3124 if (!NILP (value))
3125 {
3126 background = x_alloc_image_color (f, img, value, background);
3127 img->background = background;
3128 img->background_valid = 1;
3129 non_default_colors = 1;
3130 }
3131
1f026899 3132 Create_Pixmap_From_Bitmap_Data (f, img, data,
4ef0d4d0
KS
3133 foreground, background,
3134 non_default_colors);
3135 xfree (data);
3136
3137 if (img->pixmap == NO_PIXMAP)
3138 {
3139 x_clear_image (f, img);
3140 image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil);
3141 }
3142 else
3143 success_p = 1;
3144 }
3145 else
3146 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
3147
3148 return success_p;
3149}
3150
3151
3152/* Value is non-zero if DATA looks like an in-memory XBM file. */
3153
3154static int
3155xbm_file_p (data)
3156 Lisp_Object data;
3157{
3158 int w, h;
3159 return (STRINGP (data)
f1f25b99 3160 && xbm_read_bitmap_data (NULL, SDATA (data),
ce959360
CY
3161 (SDATA (data) + SBYTES (data)),
3162 &w, &h, NULL, 1));
4ef0d4d0
KS
3163}
3164
3165
3166/* Fill image IMG which is used on frame F with pixmap data. Value is
3167 non-zero if successful. */
3168
3169static int
3170xbm_load (f, img)
3171 struct frame *f;
3172 struct image *img;
3173{
3174 int success_p = 0;
3175 Lisp_Object file_name;
3176
3177 xassert (xbm_image_p (img->spec));
3178
3179 /* If IMG->spec specifies a file name, create a non-file spec from it. */
3180 file_name = image_spec_value (img->spec, QCfile, NULL);
3181 if (STRINGP (file_name))
3182 {
3183 Lisp_Object file;
3184 unsigned char *contents;
3185 int size;
3186 struct gcpro gcpro1;
3187
3188 file = x_find_image_file (file_name);
3189 GCPRO1 (file);
3190 if (!STRINGP (file))
3191 {
3192 image_error ("Cannot find image file `%s'", file_name, Qnil);
3193 UNGCPRO;
3194 return 0;
3195 }
3196
3197 contents = slurp_file (SDATA (file), &size);
3198 if (contents == NULL)
3199 {
3200 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
3201 UNGCPRO;
3202 return 0;
3203 }
3204
3205 success_p = xbm_load_image (f, img, contents, contents + size);
3206 UNGCPRO;
3207 }
3208 else
3209 {
3210 struct image_keyword fmt[XBM_LAST];
3211 Lisp_Object data;
3212 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
3213 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
3214 int non_default_colors = 0;
3215 char *bits;
3216 int parsed_p;
3217 int in_memory_file_p = 0;
3218
3219 /* See if data looks like an in-memory XBM file. */
3220 data = image_spec_value (img->spec, QCdata, NULL);
3221 in_memory_file_p = xbm_file_p (data);
3222
3223 /* Parse the image specification. */
3224 bcopy (xbm_format, fmt, sizeof fmt);
3225 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
3226 xassert (parsed_p);
3227
3228 /* Get specified width, and height. */
3229 if (!in_memory_file_p)
3230 {
3231 img->width = XFASTINT (fmt[XBM_WIDTH].value);
3232 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
3233 xassert (img->width > 0 && img->height > 0);
3234 }
3235
3236 /* Get foreground and background colors, maybe allocate colors. */
3237 if (fmt[XBM_FOREGROUND].count
3238 && STRINGP (fmt[XBM_FOREGROUND].value))
3239 {
3240 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
3241 foreground);
3242 non_default_colors = 1;
3243 }
3244
3245 if (fmt[XBM_BACKGROUND].count
3246 && STRINGP (fmt[XBM_BACKGROUND].value))
3247 {
3248 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
3249 background);
3250 non_default_colors = 1;
3251 }
3252
3253 if (in_memory_file_p)
3254 success_p = xbm_load_image (f, img, SDATA (data),
3255 (SDATA (data)
3256 + SBYTES (data)));
3257 else
3258 {
3259 if (VECTORP (data))
3260 {
3261 int i;
3262 char *p;
3263 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
3264
3265 p = bits = (char *) alloca (nbytes * img->height);
3266 for (i = 0; i < img->height; ++i, p += nbytes)
3267 {
3268 Lisp_Object line = XVECTOR (data)->contents[i];
3269 if (STRINGP (line))
3270 bcopy (SDATA (line), p, nbytes);
3271 else
3272 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
3273 }
3274 }
3275 else if (STRINGP (data))
3276 bits = SDATA (data);
3277 else
3278 bits = XBOOL_VECTOR (data)->data;
3279
44b1dc2e
JR
3280#ifdef WINDOWSNT
3281 {
3282 char *invertedBits;
3283 int nbytes, i;
3284 /* Windows mono bitmaps are reversed compared with X. */
3285 invertedBits = bits;
3286 nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR
3287 * img->height;
3288 bits = (char *) alloca(nbytes);
3289 for (i = 0; i < nbytes; i++)
3290 bits[i] = XBM_BIT_SHUFFLE (invertedBits[i]);
3291 }
3292#endif
4ef0d4d0
KS
3293 /* Create the pixmap. */
3294
3295 Create_Pixmap_From_Bitmap_Data (f, img, bits,
3296 foreground, background,
3297 non_default_colors);
3298 if (img->pixmap)
3299 success_p = 1;
3300 else
3301 {
3302 image_error ("Unable to create pixmap for XBM image `%s'",
3303 img->spec, Qnil);
3304 x_clear_image (f, img);
3305 }
3306 }
3307 }
3308
3309 return success_p;
3310}
3311
3312
3313\f
3314/***********************************************************************
3315 XPM images
3316 ***********************************************************************/
3317
9e2a2647 3318#if defined (HAVE_XPM) || defined (HAVE_NS)
4ef0d4d0
KS
3319
3320static int xpm_image_p P_ ((Lisp_Object object));
3321static int xpm_load P_ ((struct frame *f, struct image *img));
3322static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
3323
9e2a2647 3324#endif /* HAVE_XPM || HAVE_NS */
ea1aaa6f
ST
3325
3326#ifdef HAVE_XPM
4ef0d4d0
KS
3327#ifdef HAVE_NTGUI
3328/* Indicate to xpm.h that we don't have Xlib. */
3329#define FOR_MSW
3330/* simx.h in xpm defines XColor and XImage differently than Emacs. */
279d3293 3331/* It also defines Display the same way as Emacs, but gcc 3.3 still barfs. */
4ef0d4d0
KS
3332#define XColor xpm_XColor
3333#define XImage xpm_XImage
279d3293 3334#define Display xpm_Display
4ef0d4d0
KS
3335#define PIXEL_ALREADY_TYPEDEFED
3336#include "X11/xpm.h"
3337#undef FOR_MSW
3338#undef XColor
3339#undef XImage
279d3293 3340#undef Display
4ef0d4d0
KS
3341#undef PIXEL_ALREADY_TYPEDEFED
3342#else
3343#include "X11/xpm.h"
3344#endif /* HAVE_NTGUI */
ea1aaa6f 3345#endif /* HAVE_XPM */
4ef0d4d0 3346
9e2a2647 3347#if defined (HAVE_XPM) || defined (HAVE_NS)
4ef0d4d0
KS
3348/* The symbol `xpm' identifying XPM-format images. */
3349
3350Lisp_Object Qxpm;
3351
3352/* Indices of image specification fields in xpm_format, below. */
3353
3354enum xpm_keyword_index
3355{
3356 XPM_TYPE,
3357 XPM_FILE,
3358 XPM_DATA,
3359 XPM_ASCENT,
3360 XPM_MARGIN,
3361 XPM_RELIEF,
3362 XPM_ALGORITHM,
3363 XPM_HEURISTIC_MASK,
3364 XPM_MASK,
3365 XPM_COLOR_SYMBOLS,
3366 XPM_BACKGROUND,
3367 XPM_LAST
3368};
3369
3370/* Vector of image_keyword structures describing the format
3371 of valid XPM image specifications. */
3372
3373static struct image_keyword xpm_format[XPM_LAST] =
3374{
3375 {":type", IMAGE_SYMBOL_VALUE, 1},
3376 {":file", IMAGE_STRING_VALUE, 0},
3377 {":data", IMAGE_STRING_VALUE, 0},
3378 {":ascent", IMAGE_ASCENT_VALUE, 0},
3379 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
3380 {":relief", IMAGE_INTEGER_VALUE, 0},
3381 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3382 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3383 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3384 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3385 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
3386};
3387
3388/* Structure describing the image type XPM. */
3389
3390static struct image_type xpm_type =
3391{
3392 &Qxpm,
3393 xpm_image_p,
3394 xpm_load,
3395 x_clear_image,
3396 NULL
3397};
3398
3399#ifdef HAVE_X_WINDOWS
3400
3401/* Define ALLOC_XPM_COLORS if we can use Emacs' own color allocation
3402 functions for allocating image colors. Our own functions handle
3403 color allocation failures more gracefully than the ones on the XPM
3404 lib. */
3405
3406#if defined XpmAllocColor && defined XpmFreeColors && defined XpmColorClosure
3407#define ALLOC_XPM_COLORS
3408#endif
3409#endif /* HAVE_X_WINDOWS */
3410
3411#ifdef ALLOC_XPM_COLORS
3412
3413static void xpm_init_color_cache P_ ((struct frame *, XpmAttributes *));
3414static void xpm_free_color_cache P_ ((void));
3415static int xpm_lookup_color P_ ((struct frame *, char *, XColor *));
3416static int xpm_color_bucket P_ ((char *));
3417static struct xpm_cached_color *xpm_cache_color P_ ((struct frame *, char *,
3418 XColor *, int));
3419
3420/* An entry in a hash table used to cache color definitions of named
3421 colors. This cache is necessary to speed up XPM image loading in
3422 case we do color allocations ourselves. Without it, we would need
3423 a call to XParseColor per pixel in the image. */
3424
3425struct xpm_cached_color
3426{
3427 /* Next in collision chain. */
3428 struct xpm_cached_color *next;
3429
3430 /* Color definition (RGB and pixel color). */
3431 XColor color;
3432
3433 /* Color name. */
3434 char name[1];
3435};
3436
3437/* The hash table used for the color cache, and its bucket vector
3438 size. */
3439
3440#define XPM_COLOR_CACHE_BUCKETS 1001
3441struct xpm_cached_color **xpm_color_cache;
3442
3443/* Initialize the color cache. */
3444
3445static void
3446xpm_init_color_cache (f, attrs)
3447 struct frame *f;
3448 XpmAttributes *attrs;
3449{
3450 size_t nbytes = XPM_COLOR_CACHE_BUCKETS * sizeof *xpm_color_cache;
3451 xpm_color_cache = (struct xpm_cached_color **) xmalloc (nbytes);
3452 memset (xpm_color_cache, 0, nbytes);
3453 init_color_table ();
3454
3455 if (attrs->valuemask & XpmColorSymbols)
3456 {
3457 int i;
3458 XColor color;
3459
3460 for (i = 0; i < attrs->numsymbols; ++i)
3461 if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
3462 attrs->colorsymbols[i].value, &color))
3463 {
3464 color.pixel = lookup_rgb_color (f, color.red, color.green,
3465 color.blue);
3466 xpm_cache_color (f, attrs->colorsymbols[i].name, &color, -1);
3467 }
3468 }
3469}
3470
3471/* Free the color cache. */
3472
3473static void
3474xpm_free_color_cache ()
3475{
3476 struct xpm_cached_color *p, *next;
3477 int i;
3478
3479 for (i = 0; i < XPM_COLOR_CACHE_BUCKETS; ++i)
3480 for (p = xpm_color_cache[i]; p; p = next)
3481 {
3482 next = p->next;
3483 xfree (p);
3484 }
3485
3486 xfree (xpm_color_cache);
3487 xpm_color_cache = NULL;
3488 free_color_table ();
3489}
3490
3491/* Return the bucket index for color named COLOR_NAME in the color
3492 cache. */
3493
3494static int
3495xpm_color_bucket (color_name)
3496 char *color_name;
3497{
3498 unsigned h = 0;
3499 char *s;
3500
3501 for (s = color_name; *s; ++s)
3502 h = (h << 2) ^ *s;
3503 return h %= XPM_COLOR_CACHE_BUCKETS;
3504}
3505
3506
3507/* On frame F, cache values COLOR for color with name COLOR_NAME.
3508 BUCKET, if >= 0, is a precomputed bucket index. Value is the cache
3509 entry added. */
3510
3511static struct xpm_cached_color *
3512xpm_cache_color (f, color_name, color, bucket)
3513 struct frame *f;
3514 char *color_name;
3515 XColor *color;
3516 int bucket;
3517{
3518 size_t nbytes;
3519 struct xpm_cached_color *p;
3520
3521 if (bucket < 0)
3522 bucket = xpm_color_bucket (color_name);
3523
3524 nbytes = sizeof *p + strlen (color_name);
3525 p = (struct xpm_cached_color *) xmalloc (nbytes);
3526 strcpy (p->name, color_name);
3527 p->color = *color;
3528 p->next = xpm_color_cache[bucket];
3529 xpm_color_cache[bucket] = p;
3530 return p;
3531}
3532
3533/* Look up color COLOR_NAME for frame F in the color cache. If found,
3534 return the cached definition in *COLOR. Otherwise, make a new
3535 entry in the cache and allocate the color. Value is zero if color
3536 allocation failed. */
3537
3538static int
3539xpm_lookup_color (f, color_name, color)
3540 struct frame *f;
3541 char *color_name;
3542 XColor *color;
3543{
3544 struct xpm_cached_color *p;
3545 int h = xpm_color_bucket (color_name);
3546
3547 for (p = xpm_color_cache[h]; p; p = p->next)
3548 if (strcmp (p->name, color_name) == 0)
3549 break;
3550
3551 if (p != NULL)
3552 *color = p->color;
3553 else if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
3554 color_name, color))
3555 {
3556 color->pixel = lookup_rgb_color (f, color->red, color->green,
3557 color->blue);
3558 p = xpm_cache_color (f, color_name, color, h);
3559 }
3560 /* You get `opaque' at least from ImageMagick converting pbm to xpm
3561 with transparency, and it's useful. */
3562 else if (strcmp ("opaque", color_name) == 0)
3563 {
3564 bzero (color, sizeof (XColor)); /* Is this necessary/correct? */
3565 color->pixel = FRAME_FOREGROUND_PIXEL (f);
3566 p = xpm_cache_color (f, color_name, color, h);
3567 }
3568
3569 return p != NULL;
3570}
3571
3572
3573/* Callback for allocating color COLOR_NAME. Called from the XPM lib.
3574 CLOSURE is a pointer to the frame on which we allocate the
3575 color. Return in *COLOR the allocated color. Value is non-zero
3576 if successful. */
3577
3578static int
3579xpm_alloc_color (dpy, cmap, color_name, color, closure)
3580 Display *dpy;
3581 Colormap cmap;
3582 char *color_name;
3583 XColor *color;
3584 void *closure;
3585{
3586 return xpm_lookup_color ((struct frame *) closure, color_name, color);
3587}
3588
3589
3590/* Callback for freeing NPIXELS colors contained in PIXELS. CLOSURE
3591 is a pointer to the frame on which we allocate the color. Value is
3592 non-zero if successful. */
3593
3594static int
3595xpm_free_colors (dpy, cmap, pixels, npixels, closure)
3596 Display *dpy;
3597 Colormap cmap;
3598 Pixel *pixels;
3599 int npixels;
3600 void *closure;
3601{
3602 return 1;
3603}
3604
3605#endif /* ALLOC_XPM_COLORS */
3606
3607
3608#ifdef HAVE_NTGUI
3609
3610/* XPM library details. */
3611
3612DEF_IMGLIB_FN (XpmFreeAttributes);
3613DEF_IMGLIB_FN (XpmCreateImageFromBuffer);
3614DEF_IMGLIB_FN (XpmReadFileToImage);
3615DEF_IMGLIB_FN (XImageFree);
3616
4ef0d4d0 3617static int
0855eb52 3618init_xpm_functions (Lisp_Object libraries)
4ef0d4d0
KS
3619{
3620 HMODULE library;
3621
0855eb52 3622 if (!(library = w32_delayed_load (libraries, Qxpm)))
4ef0d4d0
KS
3623 return 0;
3624
3625 LOAD_IMGLIB_FN (library, XpmFreeAttributes);
3626 LOAD_IMGLIB_FN (library, XpmCreateImageFromBuffer);
3627 LOAD_IMGLIB_FN (library, XpmReadFileToImage);
3628 LOAD_IMGLIB_FN (library, XImageFree);
3629 return 1;
3630}
3631
3632#endif /* HAVE_NTGUI */
3633
3634
3635/* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
3636 for XPM images. Such a list must consist of conses whose car and
3637 cdr are strings. */
3638
3639static int
3640xpm_valid_color_symbols_p (color_symbols)
3641 Lisp_Object color_symbols;
3642{
3643 while (CONSP (color_symbols))
3644 {
3645 Lisp_Object sym = XCAR (color_symbols);
3646 if (!CONSP (sym)
3647 || !STRINGP (XCAR (sym))
3648 || !STRINGP (XCDR (sym)))
3649 break;
3650 color_symbols = XCDR (color_symbols);
3651 }
3652
3653 return NILP (color_symbols);
3654}
3655
3656
3657/* Value is non-zero if OBJECT is a valid XPM image specification. */
3658
3659static int
3660xpm_image_p (object)
3661 Lisp_Object object;
3662{
3663 struct image_keyword fmt[XPM_LAST];
3664 bcopy (xpm_format, fmt, sizeof fmt);
3665 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
3666 /* Either `:file' or `:data' must be present. */
3667 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
3668 /* Either no `:color-symbols' or it's a list of conses
3669 whose car and cdr are strings. */
3670 && (fmt[XPM_COLOR_SYMBOLS].count == 0
3671 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value)));
3672}
3673
9e2a2647 3674#endif /* HAVE_XPM || HAVE_NS */
4ef0d4d0 3675
786a43d6
CY
3676#if defined (HAVE_XPM) && defined (HAVE_X_WINDOWS)
3677int
3678x_create_bitmap_from_xpm_data (f, bits)
3679 struct frame *f;
3680 char **bits;
3681{
3682 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3683 int id, rc;
3684 XpmAttributes attrs;
3685 Pixmap bitmap, mask;
3686
3687 bzero (&attrs, sizeof attrs);
3688
54188d8f
CY
3689 attrs.visual = FRAME_X_VISUAL (f);
3690 attrs.colormap = FRAME_X_COLORMAP (f);
3691 attrs.valuemask |= XpmVisual;
3692 attrs.valuemask |= XpmColormap;
3693
786a43d6
CY
3694 rc = XpmCreatePixmapFromData (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
3695 bits, &bitmap, &mask, &attrs);
3696 if (rc != XpmSuccess)
fe45ad15
CY
3697 {
3698 XpmFreeAttributes (&attrs);
3699 return -1;
3700 }
786a43d6
CY
3701
3702 id = x_allocate_bitmap_record (f);
786a43d6
CY
3703 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
3704 dpyinfo->bitmaps[id - 1].have_mask = 1;
3705 dpyinfo->bitmaps[id - 1].mask = mask;
3706 dpyinfo->bitmaps[id - 1].file = NULL;
3707 dpyinfo->bitmaps[id - 1].height = attrs.height;
3708 dpyinfo->bitmaps[id - 1].width = attrs.width;
3709 dpyinfo->bitmaps[id - 1].depth = attrs.depth;
3710 dpyinfo->bitmaps[id - 1].refcount = 1;
3711
3712 XpmFreeAttributes (&attrs);
3713 return id;
3714}
0d876a14 3715#endif /* defined (HAVE_XPM) && defined (HAVE_X_WINDOWS) */
786a43d6 3716
4ef0d4d0
KS
3717/* Load image IMG which will be displayed on frame F. Value is
3718 non-zero if successful. */
3719
ea1aaa6f
ST
3720#ifdef HAVE_XPM
3721
4ef0d4d0
KS
3722static int
3723xpm_load (f, img)
3724 struct frame *f;
3725 struct image *img;
3726{
3727 int rc;
3728 XpmAttributes attrs;
3729 Lisp_Object specified_file, color_symbols;
3730#ifdef HAVE_NTGUI
3731 HDC hdc;
3732 xpm_XImage * xpm_image = NULL, * xpm_mask = NULL;
3733#endif /* HAVE_NTGUI */
3734
3735 /* Configure the XPM lib. Use the visual of frame F. Allocate
3736 close colors. Return colors allocated. */
3737 bzero (&attrs, sizeof attrs);
3738
3739#ifndef HAVE_NTGUI
3740 attrs.visual = FRAME_X_VISUAL (f);
3741 attrs.colormap = FRAME_X_COLORMAP (f);
3742 attrs.valuemask |= XpmVisual;
3743 attrs.valuemask |= XpmColormap;
3744#endif /* HAVE_NTGUI */
3745
3746#ifdef ALLOC_XPM_COLORS
3747 /* Allocate colors with our own functions which handle
3748 failing color allocation more gracefully. */
3749 attrs.color_closure = f;
3750 attrs.alloc_color = xpm_alloc_color;
3751 attrs.free_colors = xpm_free_colors;
3752 attrs.valuemask |= XpmAllocColor | XpmFreeColors | XpmColorClosure;
3753#else /* not ALLOC_XPM_COLORS */
3754 /* Let the XPM lib allocate colors. */
3755 attrs.valuemask |= XpmReturnAllocPixels;
3756#ifdef XpmAllocCloseColors
3757 attrs.alloc_close_colors = 1;
3758 attrs.valuemask |= XpmAllocCloseColors;
3759#else /* not XpmAllocCloseColors */
3760 attrs.closeness = 600;
3761 attrs.valuemask |= XpmCloseness;
3762#endif /* not XpmAllocCloseColors */
3763#endif /* ALLOC_XPM_COLORS */
3764
3765 /* If image specification contains symbolic color definitions, add
3766 these to `attrs'. */
3767 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
3768 if (CONSP (color_symbols))
3769 {
3770 Lisp_Object tail;
3771 XpmColorSymbol *xpm_syms;
3772 int i, size;
3773
3774 attrs.valuemask |= XpmColorSymbols;
3775
3776 /* Count number of symbols. */
3777 attrs.numsymbols = 0;
3778 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
3779 ++attrs.numsymbols;
3780
3781 /* Allocate an XpmColorSymbol array. */
3782 size = attrs.numsymbols * sizeof *xpm_syms;
3783 xpm_syms = (XpmColorSymbol *) alloca (size);
3784 bzero (xpm_syms, size);
3785 attrs.colorsymbols = xpm_syms;
3786
3787 /* Fill the color symbol array. */
3788 for (tail = color_symbols, i = 0;
3789 CONSP (tail);
3790 ++i, tail = XCDR (tail))
3791 {
3792 Lisp_Object name = XCAR (XCAR (tail));
3793 Lisp_Object color = XCDR (XCAR (tail));
3794 xpm_syms[i].name = (char *) alloca (SCHARS (name) + 1);
3795 strcpy (xpm_syms[i].name, SDATA (name));
3796 xpm_syms[i].value = (char *) alloca (SCHARS (color) + 1);
3797 strcpy (xpm_syms[i].value, SDATA (color));
3798 }
3799 }
3800
3801 /* Create a pixmap for the image, either from a file, or from a
3802 string buffer containing data in the same format as an XPM file. */
3803#ifdef ALLOC_XPM_COLORS
3804 xpm_init_color_cache (f, &attrs);
3805#endif
3806
3807 specified_file = image_spec_value (img->spec, QCfile, NULL);
3808
3809#ifdef HAVE_NTGUI
3810 {
3811 HDC frame_dc = get_frame_dc (f);
3812 hdc = CreateCompatibleDC (frame_dc);
3813 release_frame_dc (f, frame_dc);
3814 }
3815#endif /* HAVE_NTGUI */
3816
3817 if (STRINGP (specified_file))
3818 {
3819 Lisp_Object file = x_find_image_file (specified_file);
3820 if (!STRINGP (file))
3821 {
3822 image_error ("Cannot find image file `%s'", specified_file, Qnil);
3823 return 0;
3824 }
3825
3826#ifdef HAVE_NTGUI
3827 /* XpmReadFileToPixmap is not available in the Windows port of
3828 libxpm. But XpmReadFileToImage almost does what we want. */
3829 rc = fn_XpmReadFileToImage (&hdc, SDATA (file),
3830 &xpm_image, &xpm_mask,
3831 &attrs);
3832#else
3833 rc = XpmReadFileToPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
3834 SDATA (file), &img->pixmap, &img->mask,
3835 &attrs);
3836#endif /* HAVE_NTGUI */
3837 }
3838 else
3839 {
3840 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
3841#ifdef HAVE_NTGUI
3842 /* XpmCreatePixmapFromBuffer is not available in the Windows port
3843 of libxpm. But XpmCreateImageFromBuffer almost does what we want. */
3844 rc = fn_XpmCreateImageFromBuffer (&hdc, SDATA (buffer),
3845 &xpm_image, &xpm_mask,
3846 &attrs);
3847#else
3848 rc = XpmCreatePixmapFromBuffer (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
3849 SDATA (buffer),
3850 &img->pixmap, &img->mask,
3851 &attrs);
3852#endif /* HAVE_NTGUI */
3853 }
3854
3855 if (rc == XpmSuccess)
3856 {
3857#if defined (COLOR_TABLE_SUPPORT) && defined (ALLOC_XPM_COLORS)
3858 img->colors = colors_in_color_table (&img->ncolors);
3859#else /* not ALLOC_XPM_COLORS */
3860 int i;
3861
3862#ifdef HAVE_NTGUI
3863 /* W32 XPM uses XImage to wrap what W32 Emacs calls a Pixmap,
3864 plus some duplicate attributes. */
3865 if (xpm_image && xpm_image->bitmap)
3866 {
3867 img->pixmap = xpm_image->bitmap;
3868 /* XImageFree in libXpm frees XImage struct without destroying
3869 the bitmap, which is what we want. */
3870 fn_XImageFree (xpm_image);
3871 }
3872 if (xpm_mask && xpm_mask->bitmap)
3873 {
3874 /* The mask appears to be inverted compared with what we expect.
3875 TODO: invert our expectations. See other places where we
3876 have to invert bits because our idea of masks is backwards. */
3877 HGDIOBJ old_obj;
3878 old_obj = SelectObject (hdc, xpm_mask->bitmap);
3879
3880 PatBlt (hdc, 0, 0, xpm_mask->width, xpm_mask->height, DSTINVERT);
3881 SelectObject (hdc, old_obj);
3882
3883 img->mask = xpm_mask->bitmap;
3884 fn_XImageFree (xpm_mask);
3885 DeleteDC (hdc);
3886 }
3887
3888 DeleteDC (hdc);
3889#endif /* HAVE_NTGUI */
3890
3891 /* Remember allocated colors. */
3892 img->ncolors = attrs.nalloc_pixels;
3893 img->colors = (unsigned long *) xmalloc (img->ncolors
3894 * sizeof *img->colors);
3895 for (i = 0; i < attrs.nalloc_pixels; ++i)
3896 {
3897 img->colors[i] = attrs.alloc_pixels[i];
3898#ifdef DEBUG_X_COLORS
3899 register_color (img->colors[i]);
3900#endif
3901 }
3902#endif /* not ALLOC_XPM_COLORS */
3903
3904 img->width = attrs.width;
3905 img->height = attrs.height;
3906 xassert (img->width > 0 && img->height > 0);
3907
3908 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
3909#ifdef HAVE_NTGUI
3910 fn_XpmFreeAttributes (&attrs);
3911#else
3912 XpmFreeAttributes (&attrs);
3913#endif /* HAVE_NTGUI */
3914 }
3915 else
3916 {
3917#ifdef HAVE_NTGUI
3918 DeleteDC (hdc);
3919#endif /* HAVE_NTGUI */
3920
3921 switch (rc)
3922 {
3923 case XpmOpenFailed:
3924 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
3925 break;
3926
3927 case XpmFileInvalid:
3928 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
3929 break;
3930
3931 case XpmNoMemory:
3932 image_error ("Out of memory (%s)", img->spec, Qnil);
3933 break;
3934
3935 case XpmColorFailed:
3936 image_error ("Color allocation error (%s)", img->spec, Qnil);
3937 break;
3938
3939 default:
3940 image_error ("Unknown error (%s)", img->spec, Qnil);
3941 break;
3942 }
3943 }
3944
3945#ifdef ALLOC_XPM_COLORS
3946 xpm_free_color_cache ();
3947#endif
3948 return rc == XpmSuccess;
3949}
3950
3951#endif /* HAVE_XPM */
3952
9e2a2647 3953#if defined (HAVE_NS) && !defined (HAVE_XPM)
ea1aaa6f 3954
9e2a2647 3955/* XPM support functions for NS where libxpm is not available.
ea1aaa6f
ST
3956 Only XPM version 3 (without any extensions) is supported. */
3957
46accb8f
YM
3958static int xpm_scan P_ ((const unsigned char **, const unsigned char *,
3959 const unsigned char **, int *));
ea1aaa6f 3960static Lisp_Object xpm_make_color_table_v
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_v P_ ((Lisp_Object, const unsigned char *,
9ecf6403 3964 int, Lisp_Object));
ea1aaa6f 3965static Lisp_Object xpm_get_color_table_v P_ ((Lisp_Object,
46accb8f 3966 const unsigned char *, int));
ea1aaa6f 3967static Lisp_Object xpm_make_color_table_h
46accb8f
YM
3968 P_ ((void (**) (Lisp_Object, const unsigned char *, int, Lisp_Object),
3969 Lisp_Object (**) (Lisp_Object, const unsigned char *, int)));
3970static void xpm_put_color_table_h P_ ((Lisp_Object, const unsigned char *,
9ecf6403 3971 int, Lisp_Object));
ea1aaa6f 3972static Lisp_Object xpm_get_color_table_h P_ ((Lisp_Object,
46accb8f
YM
3973 const unsigned char *, int));
3974static int xpm_str_to_color_key P_ ((const char *));
ea1aaa6f 3975static int xpm_load_image P_ ((struct frame *, struct image *,
46accb8f 3976 const unsigned char *, const unsigned char *));
ea1aaa6f
ST
3977
3978/* Tokens returned from xpm_scan. */
3979
3980enum xpm_token
3981{
3982 XPM_TK_IDENT = 256,
3983 XPM_TK_STRING,
3984 XPM_TK_EOF
3985};
3986
3987/* Scan an XPM data and return a character (< 256) or a token defined
3988 by enum xpm_token above. *S and END are the start (inclusive) and
3989 the end (exclusive) addresses of the data, respectively. Advance
3990 *S while scanning. If token is either XPM_TK_IDENT or
3991 XPM_TK_STRING, *BEG and *LEN are set to the start address and the
3992 length of the corresponding token, respectively. */
3993
3994static int
3995xpm_scan (s, end, beg, len)
46accb8f 3996 const unsigned char **s, *end, **beg;
ea1aaa6f
ST
3997 int *len;
3998{
3999 int c;
4000
4001 while (*s < end)
4002 {
4003 /* Skip white-space. */
4004 while (*s < end && (c = *(*s)++, isspace (c)))
9ecf6403 4005 ;
ea1aaa6f
ST
4006
4007 /* gnus-pointer.xpm uses '-' in its identifier.
9ecf6403 4008 sb-dir-plus.xpm uses '+' in its identifier. */
ea1aaa6f 4009 if (isalpha (c) || c == '_' || c == '-' || c == '+')
9ecf6403
YM
4010 {
4011 *beg = *s - 1;
2ff0845e
YM
4012 while (*s < end
4013 && (c = **s, isalnum (c) || c == '_' || c == '-' || c == '+'))
9ecf6403
YM
4014 ++*s;
4015 *len = *s - *beg;
4016 return XPM_TK_IDENT;
4017 }
ea1aaa6f 4018 else if (c == '"')
9ecf6403
YM
4019 {
4020 *beg = *s;
4021 while (*s < end && **s != '"')
4022 ++*s;
4023 *len = *s - *beg;
4024 if (*s < end)
4025 ++*s;
4026 return XPM_TK_STRING;
4027 }
ea1aaa6f 4028 else if (c == '/')
9ecf6403
YM
4029 {
4030 if (*s < end && **s == '*')
4031 {
4032 /* C-style comment. */
4033 ++*s;
4034 do
4035 {
4036 while (*s < end && *(*s)++ != '*')
4037 ;
4038 }
4039 while (*s < end && **s != '/');
4040 if (*s < end)
4041 ++*s;
4042 }
4043 else
4044 return c;
4045 }
ea1aaa6f 4046 else
9ecf6403 4047 return c;
ea1aaa6f
ST
4048 }
4049
4050 return XPM_TK_EOF;
4051}
4052
bbe6f2aa 4053/* Functions for color table lookup in XPM data. A key is a string
ea1aaa6f
ST
4054 specifying the color of each pixel in XPM data. A value is either
4055 an integer that specifies a pixel color, Qt that specifies
4056 transparency, or Qnil for the unspecified color. If the length of
4057 the key string is one, a vector is used as a table. Otherwise, a
4058 hash table is used. */
4059
4060static Lisp_Object
4061xpm_make_color_table_v (put_func, get_func)
46accb8f
YM
4062 void (**put_func) (Lisp_Object, const unsigned char *, int, Lisp_Object);
4063 Lisp_Object (**get_func) (Lisp_Object, const unsigned char *, int);
ea1aaa6f
ST
4064{
4065 *put_func = xpm_put_color_table_v;
4066 *get_func = xpm_get_color_table_v;
4067 return Fmake_vector (make_number (256), Qnil);
4068}
4069
4070static void
4071xpm_put_color_table_v (color_table, chars_start, chars_len, color)
4072 Lisp_Object color_table;
46accb8f 4073 const unsigned char *chars_start;
ea1aaa6f
ST
4074 int chars_len;
4075 Lisp_Object color;
4076{
4077 XVECTOR (color_table)->contents[*chars_start] = color;
4078}
4079
4080static Lisp_Object
4081xpm_get_color_table_v (color_table, chars_start, chars_len)
4082 Lisp_Object color_table;
46accb8f 4083 const unsigned char *chars_start;
ea1aaa6f
ST
4084 int chars_len;
4085{
4086 return XVECTOR (color_table)->contents[*chars_start];
4087}
4088
4089static Lisp_Object
4090xpm_make_color_table_h (put_func, get_func)
46accb8f
YM
4091 void (**put_func) (Lisp_Object, const unsigned char *, int, Lisp_Object);
4092 Lisp_Object (**get_func) (Lisp_Object, const unsigned char *, int);
ea1aaa6f
ST
4093{
4094 *put_func = xpm_put_color_table_h;
4095 *get_func = xpm_get_color_table_h;
4096 return make_hash_table (Qequal, make_number (DEFAULT_HASH_SIZE),
9ecf6403
YM
4097 make_float (DEFAULT_REHASH_SIZE),
4098 make_float (DEFAULT_REHASH_THRESHOLD),
4099 Qnil, Qnil, Qnil);
ea1aaa6f
ST
4100}
4101
4102static void
4103xpm_put_color_table_h (color_table, chars_start, chars_len, color)
4104 Lisp_Object color_table;
46accb8f 4105 const unsigned char *chars_start;
ea1aaa6f
ST
4106 int chars_len;
4107 Lisp_Object color;
4108{
4109 struct Lisp_Hash_Table *table = XHASH_TABLE (color_table);
4110 unsigned hash_code;
4111 Lisp_Object chars = make_unibyte_string (chars_start, chars_len);
4112
4113 hash_lookup (table, chars, &hash_code);
4114 hash_put (table, chars, color, hash_code);
4115}
4116
4117static Lisp_Object
4118xpm_get_color_table_h (color_table, chars_start, chars_len)
4119 Lisp_Object color_table;
46accb8f 4120 const unsigned char *chars_start;
ea1aaa6f
ST
4121 int chars_len;
4122{
4123 struct Lisp_Hash_Table *table = XHASH_TABLE (color_table);
4124 int i = hash_lookup (table, make_unibyte_string (chars_start, chars_len),
9ecf6403 4125 NULL);
ea1aaa6f
ST
4126
4127 return i >= 0 ? HASH_VALUE (table, i) : Qnil;
4128}
4129
4130enum xpm_color_key {
4131 XPM_COLOR_KEY_S,
4132 XPM_COLOR_KEY_M,
4133 XPM_COLOR_KEY_G4,
4134 XPM_COLOR_KEY_G,
4135 XPM_COLOR_KEY_C
4136};
4137
46accb8f 4138static const char xpm_color_key_strings[][4] = {"s", "m", "g4", "g", "c"};
ea1aaa6f
ST
4139
4140static int
4141xpm_str_to_color_key (s)
46accb8f 4142 const char *s;
ea1aaa6f
ST
4143{
4144 int i;
4145
4146 for (i = 0;
4147 i < sizeof xpm_color_key_strings / sizeof xpm_color_key_strings[0];
4148 i++)
4149 if (strcmp (xpm_color_key_strings[i], s) == 0)
4150 return i;
4151 return -1;
4152}
4153
4154static int
4155xpm_load_image (f, img, contents, end)
4156 struct frame *f;
4157 struct image *img;
46accb8f 4158 const unsigned char *contents, *end;
ea1aaa6f 4159{
46accb8f 4160 const unsigned char *s = contents, *beg, *str;
ea1aaa6f
ST
4161 unsigned char buffer[BUFSIZ];
4162 int width, height, x, y;
4163 int num_colors, chars_per_pixel;
4164 int len, LA1;
46accb8f
YM
4165 void (*put_color_table) (Lisp_Object, const unsigned char *, int, Lisp_Object);
4166 Lisp_Object (*get_color_table) (Lisp_Object, const unsigned char *, int);
ea1aaa6f
ST
4167 Lisp_Object frame, color_symbols, color_table;
4168 int best_key, have_mask = 0;
4169 XImagePtr ximg = NULL, mask_img = NULL;
4170
4171#define match() \
4172 LA1 = xpm_scan (&s, end, &beg, &len)
4173
9ecf6403
YM
4174#define expect(TOKEN) \
4175 if (LA1 != (TOKEN)) \
4176 goto failure; \
4177 else \
ea1aaa6f
ST
4178 match ()
4179
9ecf6403 4180#define expect_ident(IDENT) \
ea1aaa6f 4181 if (LA1 == XPM_TK_IDENT \
9ecf6403
YM
4182 && strlen ((IDENT)) == len && memcmp ((IDENT), beg, len) == 0) \
4183 match (); \
4184 else \
ea1aaa6f
ST
4185 goto failure
4186
4187 if (!(end - s >= 9 && memcmp (s, "/* XPM */", 9) == 0))
4188 goto failure;
4189 s += 9;
4190 match();
4191 expect_ident ("static");
4192 expect_ident ("char");
4193 expect ('*');
4194 expect (XPM_TK_IDENT);
4195 expect ('[');
4196 expect (']');
4197 expect ('=');
4198 expect ('{');
4199 expect (XPM_TK_STRING);
4200 if (len >= BUFSIZ)
4201 goto failure;
4202 memcpy (buffer, beg, len);
4203 buffer[len] = '\0';
4204 if (sscanf (buffer, "%d %d %d %d", &width, &height,
9ecf6403 4205 &num_colors, &chars_per_pixel) != 4
ea1aaa6f
ST
4206 || width <= 0 || height <= 0
4207 || num_colors <= 0 || chars_per_pixel <= 0)
4208 goto failure;
de297941
YM
4209
4210 if (!check_image_size (f, width, height))
4211 {
10ea2b82 4212 image_error ("Invalid image size (see `max-image-size')", Qnil, Qnil);
de297941
YM
4213 goto failure;
4214 }
4215
ea1aaa6f
ST
4216 expect (',');
4217
4218 XSETFRAME (frame, f);
4219 if (!NILP (Fxw_display_color_p (frame)))
4220 best_key = XPM_COLOR_KEY_C;
4221 else if (!NILP (Fx_display_grayscale_p (frame)))
4222 best_key = (XFASTINT (Fx_display_planes (frame)) > 2
9ecf6403 4223 ? XPM_COLOR_KEY_G : XPM_COLOR_KEY_G4);
ea1aaa6f
ST
4224 else
4225 best_key = XPM_COLOR_KEY_M;
4226
4227 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
4228 if (chars_per_pixel == 1)
4229 color_table = xpm_make_color_table_v (&put_color_table,
9ecf6403 4230 &get_color_table);
ea1aaa6f
ST
4231 else
4232 color_table = xpm_make_color_table_h (&put_color_table,
9ecf6403 4233 &get_color_table);
ea1aaa6f
ST
4234
4235 while (num_colors-- > 0)
4236 {
4237 unsigned char *color, *max_color;
4238 int key, next_key, max_key = 0;
4239 Lisp_Object symbol_color = Qnil, color_val;
4240 XColor cdef;
4241
4242 expect (XPM_TK_STRING);
4243 if (len <= chars_per_pixel || len >= BUFSIZ + chars_per_pixel)
9ecf6403 4244 goto failure;
ea1aaa6f
ST
4245 memcpy (buffer, beg + chars_per_pixel, len - chars_per_pixel);
4246 buffer[len - chars_per_pixel] = '\0';
4247
4248 str = strtok (buffer, " \t");
4249 if (str == NULL)
9ecf6403 4250 goto failure;
ea1aaa6f
ST
4251 key = xpm_str_to_color_key (str);
4252 if (key < 0)
9ecf6403 4253 goto failure;
ea1aaa6f 4254 do
9ecf6403
YM
4255 {
4256 color = strtok (NULL, " \t");
4257 if (color == NULL)
4258 goto failure;
ea1aaa6f 4259
9db94f82 4260 while ((str = strtok (NULL, " \t")) != NULL)
9ecf6403
YM
4261 {
4262 next_key = xpm_str_to_color_key (str);
4263 if (next_key >= 0)
4264 break;
4265 color[strlen (color)] = ' ';
4266 }
ea1aaa6f 4267
9ecf6403
YM
4268 if (key == XPM_COLOR_KEY_S)
4269 {
4270 if (NILP (symbol_color))
4271 symbol_color = build_string (color);
4272 }
4273 else if (max_key < key && key <= best_key)
4274 {
4275 max_key = key;
4276 max_color = color;
4277 }
4278 key = next_key;
4279 }
ea1aaa6f
ST
4280 while (str);
4281
4282 color_val = Qnil;
4283 if (!NILP (color_symbols) && !NILP (symbol_color))
9ecf6403
YM
4284 {
4285 Lisp_Object specified_color = Fassoc (symbol_color, color_symbols);
4286
4287 if (CONSP (specified_color) && STRINGP (XCDR (specified_color)))
9db94f82 4288 {
05131107 4289 if (xstrcasecmp (SDATA (XCDR (specified_color)), "None") == 0)
9db94f82
YM
4290 color_val = Qt;
4291 else if (x_defined_color (f, SDATA (XCDR (specified_color)),
4292 &cdef, 0))
4293 color_val = make_number (cdef.pixel);
4294 }
9ecf6403 4295 }
ea1aaa6f 4296 if (NILP (color_val) && max_key > 0)
9db94f82 4297 {
05131107 4298 if (xstrcasecmp (max_color, "None") == 0)
9db94f82
YM
4299 color_val = Qt;
4300 else if (x_defined_color (f, max_color, &cdef, 0))
4301 color_val = make_number (cdef.pixel);
4302 }
ea1aaa6f 4303 if (!NILP (color_val))
9ecf6403 4304 (*put_color_table) (color_table, beg, chars_per_pixel, color_val);
ea1aaa6f
ST
4305
4306 expect (',');
4307 }
4308
4309 if (!x_create_x_image_and_pixmap (f, width, height, 0,
9ecf6403 4310 &ximg, &img->pixmap)
edfda783 4311#ifndef HAVE_NS
ea1aaa6f 4312 || !x_create_x_image_and_pixmap (f, width, height, 1,
edfda783
AR
4313 &mask_img, &img->mask)
4314#endif
4315 )
ea1aaa6f
ST
4316 {
4317 image_error ("Out of memory (%s)", img->spec, Qnil);
4318 goto error;
4319 }
4320
4321 for (y = 0; y < height; y++)
4322 {
4323 expect (XPM_TK_STRING);
4324 str = beg;
4325 if (len < width * chars_per_pixel)
9ecf6403 4326 goto failure;
ea1aaa6f 4327 for (x = 0; x < width; x++, str += chars_per_pixel)
9ecf6403
YM
4328 {
4329 Lisp_Object color_val =
4330 (*get_color_table) (color_table, str, chars_per_pixel);
4331
4332 XPutPixel (ximg, x, y,
4333 (INTEGERP (color_val) ? XINT (color_val)
4334 : FRAME_FOREGROUND_PIXEL (f)));
edfda783 4335#ifndef HAVE_NS
9ecf6403
YM
4336 XPutPixel (mask_img, x, y,
4337 (!EQ (color_val, Qt) ? PIX_MASK_DRAW
4338 : (have_mask = 1, PIX_MASK_RETAIN)));
edfda783
AR
4339#else
4340 if (EQ(color_val, Qt))
4341 ns_set_alpha(ximg, x, y, 0);
4342#endif
9ecf6403 4343 }
ea1aaa6f 4344 if (y + 1 < height)
9ecf6403 4345 expect (',');
ea1aaa6f
ST
4346 }
4347
4348 img->width = width;
4349 img->height = height;
4350
0b8ac842
YM
4351 /* Maybe fill in the background field while we have ximg handy. */
4352 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
4353 IMAGE_BACKGROUND (img, f, ximg);
4354
ea1aaa6f
ST
4355 x_put_x_image (f, ximg, img->pixmap, width, height);
4356 x_destroy_x_image (ximg);
edfda783 4357#ifndef HAVE_NS
ea1aaa6f
ST
4358 if (have_mask)
4359 {
9ecf6403
YM
4360 /* Fill in the background_transparent field while we have the
4361 mask handy. */
4362 image_background_transparent (img, f, mask_img);
4363
ea1aaa6f
ST
4364 x_put_x_image (f, mask_img, img->mask, width, height);
4365 x_destroy_x_image (mask_img);
4366 }
4367 else
4368 {
4369 x_destroy_x_image (mask_img);
4370 Free_Pixmap (FRAME_X_DISPLAY (f), img->mask);
4371 img->mask = NO_PIXMAP;
4372 }
edfda783 4373#endif
ea1aaa6f
ST
4374 return 1;
4375
4376 failure:
4377 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
4378 error:
4379 x_destroy_x_image (ximg);
4380 x_destroy_x_image (mask_img);
4381 x_clear_image (f, img);
4382 return 0;
4383
4384#undef match
4385#undef expect
4386#undef expect_ident
4387}
4388
4389static int
4390xpm_load (f, img)
4391 struct frame *f;
4392 struct image *img;
4393{
4394 int success_p = 0;
4395 Lisp_Object file_name;
4396
4397 /* If IMG->spec specifies a file name, create a non-file spec from it. */
4398 file_name = image_spec_value (img->spec, QCfile, NULL);
4399 if (STRINGP (file_name))
4400 {
4401 Lisp_Object file;
4402 unsigned char *contents;
4403 int size;
4404 struct gcpro gcpro1;
4405
4406 file = x_find_image_file (file_name);
4407 GCPRO1 (file);
4408 if (!STRINGP (file))
9ecf6403
YM
4409 {
4410 image_error ("Cannot find image file `%s'", file_name, Qnil);
4411 UNGCPRO;
4412 return 0;
4413 }
ea1aaa6f
ST
4414
4415 contents = slurp_file (SDATA (file), &size);
4416 if (contents == NULL)
9ecf6403
YM
4417 {
4418 image_error ("Error loading XPM image `%s'", img->spec, Qnil);
4419 UNGCPRO;
4420 return 0;
4421 }
ea1aaa6f
ST
4422
4423 success_p = xpm_load_image (f, img, contents, contents + size);
4424 xfree (contents);
4425 UNGCPRO;
4426 }
4427 else
4428 {
4429 Lisp_Object data;
4430
4431 data = image_spec_value (img->spec, QCdata, NULL);
4432 success_p = xpm_load_image (f, img, SDATA (data),
9ecf6403 4433 SDATA (data) + SBYTES (data));
ea1aaa6f
ST
4434 }
4435
4436 return success_p;
4437}
4438
9e2a2647 4439#endif /* HAVE_NS && !HAVE_XPM */
b0da69a7 4440
ea1aaa6f 4441
4ef0d4d0
KS
4442\f
4443/***********************************************************************
4444 Color table
4445 ***********************************************************************/
4446
4447#ifdef COLOR_TABLE_SUPPORT
4448
4449/* An entry in the color table mapping an RGB color to a pixel color. */
4450
4451struct ct_color
4452{
4453 int r, g, b;
4454 unsigned long pixel;
4455
4456 /* Next in color table collision list. */
4457 struct ct_color *next;
4458};
4459
4460/* The bucket vector size to use. Must be prime. */
4461
4462#define CT_SIZE 101
4463
4464/* Value is a hash of the RGB color given by R, G, and B. */
4465
4466#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
4467
4468/* The color hash table. */
4469
4470struct ct_color **ct_table;
4471
4472/* Number of entries in the color table. */
4473
4474int ct_colors_allocated;
4475
4476/* Initialize the color table. */
4477
4478static void
4479init_color_table ()
4480{
4481 int size = CT_SIZE * sizeof (*ct_table);
4482 ct_table = (struct ct_color **) xmalloc (size);
4483 bzero (ct_table, size);
4484 ct_colors_allocated = 0;
4485}
4486
4487
4488/* Free memory associated with the color table. */
4489
4490static void
4491free_color_table ()
4492{
4493 int i;
4494 struct ct_color *p, *next;
4495
4496 for (i = 0; i < CT_SIZE; ++i)
4497 for (p = ct_table[i]; p; p = next)
4498 {
4499 next = p->next;
4500 xfree (p);
4501 }
4502
4503 xfree (ct_table);
4504 ct_table = NULL;
4505}
4506
4507
4508/* Value is a pixel color for RGB color R, G, B on frame F. If an
4509 entry for that color already is in the color table, return the
4510 pixel color of that entry. Otherwise, allocate a new color for R,
4511 G, B, and make an entry in the color table. */
4512
4513static unsigned long
4514lookup_rgb_color (f, r, g, b)
4515 struct frame *f;
4516 int r, g, b;
4517{
4518 unsigned hash = CT_HASH_RGB (r, g, b);
4519 int i = hash % CT_SIZE;
4520 struct ct_color *p;
4521 Display_Info *dpyinfo;
4522
4523 /* Handle TrueColor visuals specially, which improves performance by
4524 two orders of magnitude. Freeing colors on TrueColor visuals is
4525 a nop, and pixel colors specify RGB values directly. See also
4526 the Xlib spec, chapter 3.1. */
4527 dpyinfo = FRAME_X_DISPLAY_INFO (f);
4528 if (dpyinfo->red_bits > 0)
4529 {
4530 unsigned long pr, pg, pb;
4531
4532 /* Apply gamma-correction like normal color allocation does. */
4533 if (f->gamma)
4534 {
4535 XColor color;
4536 color.red = r, color.green = g, color.blue = b;
4537 gamma_correct (f, &color);
4538 r = color.red, g = color.green, b = color.blue;
4539 }
4540
4541 /* Scale down RGB values to the visual's bits per RGB, and shift
4542 them to the right position in the pixel color. Note that the
4543 original RGB values are 16-bit values, as usual in X. */
4544 pr = (r >> (16 - dpyinfo->red_bits)) << dpyinfo->red_offset;
4545 pg = (g >> (16 - dpyinfo->green_bits)) << dpyinfo->green_offset;
4546 pb = (b >> (16 - dpyinfo->blue_bits)) << dpyinfo->blue_offset;
4547
4548 /* Assemble the pixel color. */
4549 return pr | pg | pb;
4550 }
1f026899 4551
4ef0d4d0
KS
4552 for (p = ct_table[i]; p; p = p->next)
4553 if (p->r == r && p->g == g && p->b == b)
4554 break;
4555
4556 if (p == NULL)
4557 {
4558
4559#ifdef HAVE_X_WINDOWS
4560 XColor color;
4561 Colormap cmap;
4562 int rc;
4563
4564 color.red = r;
4565 color.green = g;
4566 color.blue = b;
4567
4568 cmap = FRAME_X_COLORMAP (f);
4569 rc = x_alloc_nearest_color (f, cmap, &color);
4570 if (rc)
4571 {
4572 ++ct_colors_allocated;
4573 p = (struct ct_color *) xmalloc (sizeof *p);
4574 p->r = r;
4575 p->g = g;
4576 p->b = b;
4577 p->pixel = color.pixel;
4578 p->next = ct_table[i];
4579 ct_table[i] = p;
4580 }
4581 else
4582 return FRAME_FOREGROUND_PIXEL (f);
4583
4584#else
4585 COLORREF color;
4586#ifdef HAVE_NTGUI
4587 color = PALETTERGB (r, g, b);
4588#else
4589 color = RGB_TO_ULONG (r, g, b);
4590#endif /* HAVE_NTGUI */
4591 ++ct_colors_allocated;
4592 p = (struct ct_color *) xmalloc (sizeof *p);
4593 p->r = r;
4594 p->g = g;
4595 p->b = b;
4596 p->pixel = color;
4597 p->next = ct_table[i];
4598 ct_table[i] = p;
4599#endif /* HAVE_X_WINDOWS */
4600
4601 }
4602
4603 return p->pixel;
4604}
4605
4606
4607/* Look up pixel color PIXEL which is used on frame F in the color
4608 table. If not already present, allocate it. Value is PIXEL. */
4609
4610static unsigned long
4611lookup_pixel_color (f, pixel)
4612 struct frame *f;
4613 unsigned long pixel;
4614{
4615 int i = pixel % CT_SIZE;
4616 struct ct_color *p;
4617
4618 for (p = ct_table[i]; p; p = p->next)
4619 if (p->pixel == pixel)
4620 break;
4621
4622 if (p == NULL)
4623 {
4624 XColor color;
4625 Colormap cmap;
4626 int rc;
4627
4628#ifdef HAVE_X_WINDOWS
4629 cmap = FRAME_X_COLORMAP (f);
4630 color.pixel = pixel;
4631 x_query_color (f, &color);
4632 rc = x_alloc_nearest_color (f, cmap, &color);
4633#else
4634 BLOCK_INPUT;
4635 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
4636 color.pixel = pixel;
4637 XQueryColor (NULL, cmap, &color);
4638 rc = x_alloc_nearest_color (f, cmap, &color);
4639 UNBLOCK_INPUT;
4640#endif /* HAVE_X_WINDOWS */
4641
4642 if (rc)
4643 {
4644 ++ct_colors_allocated;
4645
4646 p = (struct ct_color *) xmalloc (sizeof *p);
4647 p->r = color.red;
4648 p->g = color.green;
4649 p->b = color.blue;
4650 p->pixel = pixel;
4651 p->next = ct_table[i];
4652 ct_table[i] = p;
4653 }
4654 else
4655 return FRAME_FOREGROUND_PIXEL (f);
4656 }
4657 return p->pixel;
4658}
4659
4660
4661/* Value is a vector of all pixel colors contained in the color table,
4662 allocated via xmalloc. Set *N to the number of colors. */
4663
4664static unsigned long *
4665colors_in_color_table (n)
4666 int *n;
4667{
4668 int i, j;
4669 struct ct_color *p;
4670 unsigned long *colors;
4671
4672 if (ct_colors_allocated == 0)
4673 {
4674 *n = 0;
4675 colors = NULL;
4676 }
4677 else
4678 {
4679 colors = (unsigned long *) xmalloc (ct_colors_allocated
4680 * sizeof *colors);
4681 *n = ct_colors_allocated;
4682
4683 for (i = j = 0; i < CT_SIZE; ++i)
4684 for (p = ct_table[i]; p; p = p->next)
4685 colors[j++] = p->pixel;
4686 }
4687
4688 return colors;
4689}
4690
4691#else /* COLOR_TABLE_SUPPORT */
4692
4693static unsigned long
4694lookup_rgb_color (f, r, g, b)
4695 struct frame *f;
4696 int r, g, b;
4697{
4698 unsigned long pixel;
4699
4ef0d4d0
KS
4700#ifdef HAVE_NTGUI
4701 pixel = PALETTERGB (r >> 8, g >> 8, b >> 8);
4702#endif /* HAVE_NTGUI */
4703
edfda783
AR
4704#ifdef HAVE_NS
4705 pixel = RGB_TO_ULONG (r >> 8, g >> 8, b >> 8);
4706#endif /* HAVE_NS */
4ef0d4d0
KS
4707 return pixel;
4708}
4709
4710static void
4711init_color_table ()
4712{
4713}
4714#endif /* COLOR_TABLE_SUPPORT */
4715
4716\f
4717/***********************************************************************
4718 Algorithms
4719 ***********************************************************************/
4720
4721static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int));
4722static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *));
4723static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int));
4724
4725#ifdef HAVE_NTGUI
4726static void XPutPixel (XImagePtr , int, int, COLORREF);
4727#endif /* HAVE_NTGUI */
4728
4729/* Non-zero means draw a cross on images having `:conversion
4730 disabled'. */
4731
4732int cross_disabled_images;
4733
4734/* Edge detection matrices for different edge-detection
4735 strategies. */
4736
4737static int emboss_matrix[9] = {
4738 /* x - 1 x x + 1 */
4739 2, -1, 0, /* y - 1 */
4740 -1, 0, 1, /* y */
4741 0, 1, -2 /* y + 1 */
4742};
4743
4744static int laplace_matrix[9] = {
4745 /* x - 1 x x + 1 */
4746 1, 0, 0, /* y - 1 */
4747 0, 0, 0, /* y */
4748 0, 0, -1 /* y + 1 */
4749};
4750
4751/* Value is the intensity of the color whose red/green/blue values
4752 are R, G, and B. */
4753
4754#define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6)
4755
4756
4757/* On frame F, return an array of XColor structures describing image
4758 IMG->pixmap. Each XColor structure has its pixel color set. RGB_P
4759 non-zero means also fill the red/green/blue members of the XColor
4760 structures. Value is a pointer to the array of XColors structures,
4761 allocated with xmalloc; it must be freed by the caller. */
4762
4763static XColor *
4764x_to_xcolors (f, img, rgb_p)
4765 struct frame *f;
4766 struct image *img;
4767 int rgb_p;
4768{
4769 int x, y;
4770 XColor *colors, *p;
4771 XImagePtr_or_DC ximg;
4772#ifdef HAVE_NTGUI
4773 HDC hdc;
4774 HGDIOBJ prev;
4775#endif /* HAVE_NTGUI */
4776
4777 colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
4778
4779#ifndef HAVE_NTGUI
4780 /* Get the X image IMG->pixmap. */
4781 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
4782 0, 0, img->width, img->height, ~0, ZPixmap);
4783#else
4784 /* Load the image into a memory device context. */
4785 hdc = get_frame_dc (f);
4786 ximg = CreateCompatibleDC (hdc);
4787 release_frame_dc (f, hdc);
4788 prev = SelectObject (ximg, img->pixmap);
4789#endif /* HAVE_NTGUI */
4790
4791 /* Fill the `pixel' members of the XColor array. I wished there
4792 were an easy and portable way to circumvent XGetPixel. */
4793 p = colors;
4794 for (y = 0; y < img->height; ++y)
4795 {
4796 XColor *row = p;
4797
8b7d0a16 4798#if defined (HAVE_X_WINDOWS) || defined (HAVE_NTGUI)
4ef0d4d0 4799 for (x = 0; x < img->width; ++x, ++p)
8b7d0a16 4800 p->pixel = GET_PIXEL (ximg, x, y);
4ef0d4d0
KS
4801 if (rgb_p)
4802 x_query_colors (f, row, img->width);
4803
4804#else
4805
4806 for (x = 0; x < img->width; ++x, ++p)
4807 {
4808 /* W32_TODO: palette support needed here? */
4809 p->pixel = GET_PIXEL (ximg, x, y);
4810 if (rgb_p)
4811 {
4ef0d4d0
KS
4812 p->red = RED16_FROM_ULONG (p->pixel);
4813 p->green = GREEN16_FROM_ULONG (p->pixel);
4814 p->blue = BLUE16_FROM_ULONG (p->pixel);
4ef0d4d0
KS
4815 }
4816 }
4817#endif /* HAVE_X_WINDOWS */
4818 }
4819
4820 Destroy_Image (ximg, prev);
4821
4822 return colors;
4823}
4824
4825#ifdef HAVE_NTGUI
4826
4827/* Put a pixel of COLOR at position X, Y in XIMG. XIMG must have been
4828 created with CreateDIBSection, with the pointer to the bit values
4829 stored in ximg->data. */
4830
3046a84b
JB
4831static void
4832XPutPixel (ximg, x, y, color)
4ef0d4d0
KS
4833 XImagePtr ximg;
4834 int x, y;
4835 COLORREF color;
4836{
4837 int width = ximg->info.bmiHeader.biWidth;
4838 int height = ximg->info.bmiHeader.biHeight;
4839 unsigned char * pixel;
4840
4841 /* True color images. */
4842 if (ximg->info.bmiHeader.biBitCount == 24)
4843 {
4844 int rowbytes = width * 3;
4845 /* Ensure scanlines are aligned on 4 byte boundaries. */
4846 if (rowbytes % 4)
4847 rowbytes += 4 - (rowbytes % 4);
4848
4849 pixel = ximg->data + y * rowbytes + x * 3;
4850 /* Windows bitmaps are in BGR order. */
4851 *pixel = GetBValue (color);
4852 *(pixel + 1) = GetGValue (color);
4853 *(pixel + 2) = GetRValue (color);
4854 }
4855 /* Monochrome images. */
4856 else if (ximg->info.bmiHeader.biBitCount == 1)
4857 {
4858 int rowbytes = width / 8;
4859 /* Ensure scanlines are aligned on 4 byte boundaries. */
4860 if (rowbytes % 4)
4861 rowbytes += 4 - (rowbytes % 4);
4862 pixel = ximg->data + y * rowbytes + x / 8;
4863 /* Filter out palette info. */
4864 if (color & 0x00ffffff)
4865 *pixel = *pixel | (1 << x % 8);
4866 else
4867 *pixel = *pixel & ~(1 << x % 8);
4868 }
4869 else
4870 image_error ("XPutPixel: palette image not supported", Qnil, Qnil);
4871}
4872
4873#endif /* HAVE_NTGUI */
4874
4875/* Create IMG->pixmap from an array COLORS of XColor structures, whose
4876 RGB members are set. F is the frame on which this all happens.
4877 COLORS will be freed; an existing IMG->pixmap will be freed, too. */
4878
4879static void
4880x_from_xcolors (f, img, colors)
4881 struct frame *f;
4882 struct image *img;
4883 XColor *colors;
4884{
4885 int x, y;
edfda783 4886 XImagePtr oimg = NULL;
9d7112ed 4887 Pixmap pixmap;
4ef0d4d0
KS
4888 XColor *p;
4889
4890 init_color_table ();
4891
4892 x_create_x_image_and_pixmap (f, img->width, img->height, 0,
4893 &oimg, &pixmap);
4894 p = colors;
4895 for (y = 0; y < img->height; ++y)
4896 for (x = 0; x < img->width; ++x, ++p)
4897 {
4898 unsigned long pixel;
4899 pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
4900 XPutPixel (oimg, x, y, pixel);
4901 }
4902
4903 xfree (colors);
4904 x_clear_image_1 (f, img, 1, 0, 1);
4905
4906 x_put_x_image (f, oimg, pixmap, img->width, img->height);
4907 x_destroy_x_image (oimg);
4908 img->pixmap = pixmap;
4909#ifdef COLOR_TABLE_SUPPORT
4910 img->colors = colors_in_color_table (&img->ncolors);
4911 free_color_table ();
4912#endif /* COLOR_TABLE_SUPPORT */
4913}
4914
4915
4916/* On frame F, perform edge-detection on image IMG.
4917
4918 MATRIX is a nine-element array specifying the transformation
4919 matrix. See emboss_matrix for an example.
4920
4921 COLOR_ADJUST is a color adjustment added to each pixel of the
4922 outgoing image. */
4923
4924static void
4925x_detect_edges (f, img, matrix, color_adjust)
4926 struct frame *f;
4927 struct image *img;
4928 int matrix[9], color_adjust;
4929{
4930 XColor *colors = x_to_xcolors (f, img, 1);
4931 XColor *new, *p;
4932 int x, y, i, sum;
4933
4934 for (i = sum = 0; i < 9; ++i)
1ea40aa2 4935 sum += eabs (matrix[i]);
4ef0d4d0
KS
4936
4937#define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))
4938
4939 new = (XColor *) xmalloc (img->width * img->height * sizeof *new);
4940
4941 for (y = 0; y < img->height; ++y)
4942 {
4943 p = COLOR (new, 0, y);
4944 p->red = p->green = p->blue = 0xffff/2;
4945 p = COLOR (new, img->width - 1, y);
4946 p->red = p->green = p->blue = 0xffff/2;
4947 }
4948
4949 for (x = 1; x < img->width - 1; ++x)
4950 {
4951 p = COLOR (new, x, 0);
4952 p->red = p->green = p->blue = 0xffff/2;
4953 p = COLOR (new, x, img->height - 1);
4954 p->red = p->green = p->blue = 0xffff/2;
4955 }
4956
4957 for (y = 1; y < img->height - 1; ++y)
4958 {
4959 p = COLOR (new, 1, y);
4960
4961 for (x = 1; x < img->width - 1; ++x, ++p)
4962 {
4963 int r, g, b, y1, x1;
4964
4965 r = g = b = i = 0;
4966 for (y1 = y - 1; y1 < y + 2; ++y1)
4967 for (x1 = x - 1; x1 < x + 2; ++x1, ++i)
4968 if (matrix[i])
4969 {
4970 XColor *t = COLOR (colors, x1, y1);
4971 r += matrix[i] * t->red;
4972 g += matrix[i] * t->green;
4973 b += matrix[i] * t->blue;
4974 }
4975
4976 r = (r / sum + color_adjust) & 0xffff;
4977 g = (g / sum + color_adjust) & 0xffff;
4978 b = (b / sum + color_adjust) & 0xffff;
4979 p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b);
4980 }
4981 }
4982
4983 xfree (colors);
4984 x_from_xcolors (f, img, new);
4985
4986#undef COLOR
4987}
4988
4989
4990/* Perform the pre-defined `emboss' edge-detection on image IMG
4991 on frame F. */
4992
4993static void
4994x_emboss (f, img)
4995 struct frame *f;
4996 struct image *img;
4997{
4998 x_detect_edges (f, img, emboss_matrix, 0xffff / 2);
4999}
5000
5001
5002/* Transform image IMG which is used on frame F with a Laplace
5003 edge-detection algorithm. The result is an image that can be used
5004 to draw disabled buttons, for example. */
5005
5006static void
5007x_laplace (f, img)
5008 struct frame *f;
5009 struct image *img;
5010{
5011 x_detect_edges (f, img, laplace_matrix, 45000);
5012}
5013
5014
5015/* Perform edge-detection on image IMG on frame F, with specified
5016 transformation matrix MATRIX and color-adjustment COLOR_ADJUST.
5017
5018 MATRIX must be either
5019
5020 - a list of at least 9 numbers in row-major form
5021 - a vector of at least 9 numbers
5022
5023 COLOR_ADJUST nil means use a default; otherwise it must be a
5024 number. */
5025
5026static void
5027x_edge_detection (f, img, matrix, color_adjust)
5028 struct frame *f;
5029 struct image *img;
5030 Lisp_Object matrix, color_adjust;
5031{
5032 int i = 0;
5033 int trans[9];
5034
5035 if (CONSP (matrix))
5036 {
5037 for (i = 0;
5038 i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix));
5039 ++i, matrix = XCDR (matrix))
5040 trans[i] = XFLOATINT (XCAR (matrix));
5041 }
5042 else if (VECTORP (matrix) && ASIZE (matrix) >= 9)
5043 {
5044 for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i)
5045 trans[i] = XFLOATINT (AREF (matrix, i));
5046 }
5047
5048 if (NILP (color_adjust))
5049 color_adjust = make_number (0xffff / 2);
5050
5051 if (i == 9 && NUMBERP (color_adjust))
5052 x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust));
5053}
5054
5055
5056/* Transform image IMG on frame F so that it looks disabled. */
5057
5058static void
5059x_disable_image (f, img)
5060 struct frame *f;
5061 struct image *img;
5062{
5063 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
5064#ifdef HAVE_NTGUI
5065 int n_planes = dpyinfo->n_planes * dpyinfo->n_cbits;
5066#else
5067 int n_planes = dpyinfo->n_planes;
5068#endif /* HAVE_NTGUI */
5069
5070 if (n_planes >= 2)
5071 {
5072 /* Color (or grayscale). Convert to gray, and equalize. Just
5073 drawing such images with a stipple can look very odd, so
5074 we're using this method instead. */
5075 XColor *colors = x_to_xcolors (f, img, 1);
5076 XColor *p, *end;
5077 const int h = 15000;
5078 const int l = 30000;
5079
5080 for (p = colors, end = colors + img->width * img->height;
5081 p < end;
5082 ++p)
5083 {
5084 int i = COLOR_INTENSITY (p->red, p->green, p->blue);
5085 int i2 = (0xffff - h - l) * i / 0xffff + l;
5086 p->red = p->green = p->blue = i2;
5087 }
5088
5089 x_from_xcolors (f, img, colors);
5090 }
5091
5092 /* Draw a cross over the disabled image, if we must or if we
5093 should. */
5094 if (n_planes < 2 || cross_disabled_images)
5095 {
5096#ifndef HAVE_NTGUI
5097 Display *dpy = FRAME_X_DISPLAY (f);
5098 GC gc;
5099
5afa3a81 5100#ifndef HAVE_NS /* TODO: NS support, however this not needed for toolbars */
edfda783 5101
4ef0d4d0 5102#define MaskForeground(f) WHITE_PIX_DEFAULT (f)
4ef0d4d0 5103
ae8279db 5104 gc = XCreateGC (dpy, img->pixmap, 0, NULL);
4ef0d4d0
KS
5105 XSetForeground (dpy, gc, BLACK_PIX_DEFAULT (f));
5106 XDrawLine (dpy, img->pixmap, gc, 0, 0,
5107 img->width - 1, img->height - 1);
5108 XDrawLine (dpy, img->pixmap, gc, 0, img->height - 1,
5109 img->width - 1, 0);
5110 XFreeGC (dpy, gc);
5111
5112 if (img->mask)
5113 {
ae8279db 5114 gc = XCreateGC (dpy, img->mask, 0, NULL);
4ef0d4d0
KS
5115 XSetForeground (dpy, gc, MaskForeground (f));
5116 XDrawLine (dpy, img->mask, gc, 0, 0,
5117 img->width - 1, img->height - 1);
5118 XDrawLine (dpy, img->mask, gc, 0, img->height - 1,
5119 img->width - 1, 0);
5120 XFreeGC (dpy, gc);
5121 }
edfda783 5122#endif /* !HAVE_NS */
4ef0d4d0
KS
5123#else
5124 HDC hdc, bmpdc;
5125 HGDIOBJ prev;
5126
5127 hdc = get_frame_dc (f);
5128 bmpdc = CreateCompatibleDC (hdc);
5129 release_frame_dc (f, hdc);
5130
5131 prev = SelectObject (bmpdc, img->pixmap);
5132
5133 SetTextColor (bmpdc, BLACK_PIX_DEFAULT (f));
5134 MoveToEx (bmpdc, 0, 0, NULL);
5135 LineTo (bmpdc, img->width - 1, img->height - 1);
5136 MoveToEx (bmpdc, 0, img->height - 1, NULL);
5137 LineTo (bmpdc, img->width - 1, 0);
5138
5139 if (img->mask)
5140 {
5141 SelectObject (bmpdc, img->mask);
5142 SetTextColor (bmpdc, WHITE_PIX_DEFAULT (f));
5143 MoveToEx (bmpdc, 0, 0, NULL);
5144 LineTo (bmpdc, img->width - 1, img->height - 1);
5145 MoveToEx (bmpdc, 0, img->height - 1, NULL);
5146 LineTo (bmpdc, img->width - 1, 0);
5147 }
5148 SelectObject (bmpdc, prev);
5149 DeleteDC (bmpdc);
5150#endif /* HAVE_NTGUI */
5151 }
5152}
5153
5154
5155/* Build a mask for image IMG which is used on frame F. FILE is the
5156 name of an image file, for error messages. HOW determines how to
5157 determine the background color of IMG. If it is a list '(R G B)',
5158 with R, G, and B being integers >= 0, take that as the color of the
5159 background. Otherwise, determine the background color of IMG
5160 heuristically. Value is non-zero if successful. */
5161
5162static int
5163x_build_heuristic_mask (f, img, how)
5164 struct frame *f;
5165 struct image *img;
5166 Lisp_Object how;
5167{
5168 XImagePtr_or_DC ximg;
5169#ifndef HAVE_NTGUI
5170 XImagePtr mask_img;
5171#else
5172 HDC frame_dc;
5173 HGDIOBJ prev;
5174 char *mask_img;
5175 int row_width;
5176#endif /* HAVE_NTGUI */
5177 int x, y, rc, use_img_background;
5178 unsigned long bg = 0;
5179
5180 if (img->mask)
5181 {
5182 Free_Pixmap (FRAME_X_DISPLAY (f), img->mask);
5183 img->mask = NO_PIXMAP;
5184 img->background_transparent_valid = 0;
5185 }
5186
5187#ifndef HAVE_NTGUI
edfda783 5188#ifndef HAVE_NS
4ef0d4d0
KS
5189 /* Create an image and pixmap serving as mask. */
5190 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
5191 &mask_img, &img->mask);
5192 if (!rc)
5193 return 0;
edfda783 5194#endif /* !HAVE_NS */
4ef0d4d0
KS
5195
5196 /* Get the X image of IMG->pixmap. */
5197 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap, 0, 0,
5198 img->width, img->height,
5199 ~0, ZPixmap);
5200#else
5201 /* Create the bit array serving as mask. */
5202 row_width = (img->width + 7) / 8;
5203 mask_img = xmalloc (row_width * img->height);
5204 bzero (mask_img, row_width * img->height);
5205
5206 /* Create a memory device context for IMG->pixmap. */
5207 frame_dc = get_frame_dc (f);
5208 ximg = CreateCompatibleDC (frame_dc);
5209 release_frame_dc (f, frame_dc);
5210 prev = SelectObject (ximg, img->pixmap);
5211#endif /* HAVE_NTGUI */
5212
5213 /* Determine the background color of ximg. If HOW is `(R G B)'
5214 take that as color. Otherwise, use the image's background color. */
5215 use_img_background = 1;
5216
5217 if (CONSP (how))
5218 {
5219 int rgb[3], i;
5220
5221 for (i = 0; i < 3 && CONSP (how) && NATNUMP (XCAR (how)); ++i)
5222 {
5223 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
5224 how = XCDR (how);
5225 }
5226
5227 if (i == 3 && NILP (how))
5228 {
5229 char color_name[30];
5230 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
5231 bg = (
5232#ifdef HAVE_NTGUI
5233 0x00ffffff & /* Filter out palette info. */
5234#endif /* HAVE_NTGUI */
5235 x_alloc_image_color (f, img, build_string (color_name), 0));
5236 use_img_background = 0;
5237 }
5238 }
5239
5240 if (use_img_background)
6ac3c7bb 5241 bg = four_corners_best (ximg, img->corners, img->width, img->height);
4ef0d4d0
KS
5242
5243 /* Set all bits in mask_img to 1 whose color in ximg is different
5244 from the background color bg. */
5245#ifndef HAVE_NTGUI
5246 for (y = 0; y < img->height; ++y)
5247 for (x = 0; x < img->width; ++x)
edfda783 5248#ifndef HAVE_NS
4ef0d4d0 5249 XPutPixel (mask_img, x, y, (XGetPixel (ximg, x, y) != bg
9ecf6403 5250 ? PIX_MASK_DRAW : PIX_MASK_RETAIN));
edfda783
AR
5251#else
5252 if (XGetPixel (ximg, x, y) == bg)
5253 ns_set_alpha(ximg, x, y, 0);
5254#endif /* HAVE_NS */
5255#ifndef HAVE_NS
4ef0d4d0
KS
5256 /* Fill in the background_transparent field while we have the mask handy. */
5257 image_background_transparent (img, f, mask_img);
5258
5259 /* Put mask_img into img->mask. */
5260 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
5261 x_destroy_x_image (mask_img);
edfda783 5262#endif /* !HAVE_NS */
4ef0d4d0
KS
5263#else
5264 for (y = 0; y < img->height; ++y)
5265 for (x = 0; x < img->width; ++x)
5266 {
5267 COLORREF p = GetPixel (ximg, x, y);
5268 if (p != bg)
5269 mask_img[y * row_width + x / 8] |= 1 << (x % 8);
5270 }
5271
5272 /* Create the mask image. */
5273 img->mask = w32_create_pixmap_from_bitmap_data (img->width, img->height,
5274 mask_img);
5275 /* Fill in the background_transparent field while we have the mask handy. */
5276 SelectObject (ximg, img->mask);
5277 image_background_transparent (img, f, ximg);
5278
5279 /* Was: x_destroy_x_image ((XImagePtr )mask_img); which seems bogus ++kfs */
5280 xfree (mask_img);
5281#endif /* HAVE_NTGUI */
5282
5283 Destroy_Image (ximg, prev);
5284
5285 return 1;
5286}
5287
5288\f
5289/***********************************************************************
5290 PBM (mono, gray, color)
5291 ***********************************************************************/
5292
5293static int pbm_image_p P_ ((Lisp_Object object));
5294static int pbm_load P_ ((struct frame *f, struct image *img));
5295static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
5296
5297/* The symbol `pbm' identifying images of this type. */
5298
5299Lisp_Object Qpbm;
5300
5301/* Indices of image specification fields in gs_format, below. */
5302
5303enum pbm_keyword_index
5304{
5305 PBM_TYPE,
5306 PBM_FILE,
5307 PBM_DATA,
5308 PBM_ASCENT,
5309 PBM_MARGIN,
5310 PBM_RELIEF,
5311 PBM_ALGORITHM,
5312 PBM_HEURISTIC_MASK,
5313 PBM_MASK,
5314 PBM_FOREGROUND,
5315 PBM_BACKGROUND,
5316 PBM_LAST
5317};
5318
5319/* Vector of image_keyword structures describing the format
5320 of valid user-defined image specifications. */
5321
5322static struct image_keyword pbm_format[PBM_LAST] =
5323{
5324 {":type", IMAGE_SYMBOL_VALUE, 1},
5325 {":file", IMAGE_STRING_VALUE, 0},
5326 {":data", IMAGE_STRING_VALUE, 0},
5327 {":ascent", IMAGE_ASCENT_VALUE, 0},
5328 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
5329 {":relief", IMAGE_INTEGER_VALUE, 0},
5330 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5331 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5332 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5333 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
5334 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
5335};
5336
5337/* Structure describing the image type `pbm'. */
5338
5339static struct image_type pbm_type =
5340{
5341 &Qpbm,
5342 pbm_image_p,
5343 pbm_load,
5344 x_clear_image,
5345 NULL
5346};
5347
5348
5349/* Return non-zero if OBJECT is a valid PBM image specification. */
5350
5351static int
5352pbm_image_p (object)
5353 Lisp_Object object;
5354{
5355 struct image_keyword fmt[PBM_LAST];
5356
5357 bcopy (pbm_format, fmt, sizeof fmt);
5358
5359 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm))
5360 return 0;
5361
5362 /* Must specify either :data or :file. */
5363 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
5364}
5365
5366
5367/* Scan a decimal number from *S and return it. Advance *S while
5368 reading the number. END is the end of the string. Value is -1 at
5369 end of input. */
5370
5371static int
5372pbm_scan_number (s, end)
5373 unsigned char **s, *end;
5374{
5375 int c = 0, val = -1;
5376
5377 while (*s < end)
5378 {
5379 /* Skip white-space. */
5380 while (*s < end && (c = *(*s)++, isspace (c)))
5381 ;
5382
5383 if (c == '#')
5384 {
5385 /* Skip comment to end of line. */
5386 while (*s < end && (c = *(*s)++, c != '\n'))
5387 ;
5388 }
5389 else if (isdigit (c))
5390 {
5391 /* Read decimal number. */
5392 val = c - '0';
5393 while (*s < end && (c = *(*s)++, isdigit (c)))
5394 val = 10 * val + c - '0';
5395 break;
5396 }
5397 else
5398 break;
5399 }
5400
5401 return val;
5402}
5403
5404
5405#ifdef HAVE_NTGUI
5406#if 0 /* Unused. ++kfs */
5407
5408/* Read FILE into memory. Value is a pointer to a buffer allocated
5409 with xmalloc holding FILE's contents. Value is null if an error
5410 occurred. *SIZE is set to the size of the file. */
5411
5412static char *
5413pbm_read_file (file, size)
5414 Lisp_Object file;
5415 int *size;
5416{
5417 FILE *fp = NULL;
5418 char *buf = NULL;
5419 struct stat st;
5420
5421 if (stat (SDATA (file), &st) == 0
5422 && (fp = fopen (SDATA (file), "rb")) != NULL
5423 && (buf = (char *) xmalloc (st.st_size),
5424 fread (buf, 1, st.st_size, fp) == st.st_size))
5425 {
5426 *size = st.st_size;
5427 fclose (fp);
5428 }
5429 else
5430 {
5431 if (fp)
5432 fclose (fp);
5433 if (buf)
5434 {
5435 xfree (buf);
5436 buf = NULL;
5437 }
5438 }
5439
5440 return buf;
5441}
5442#endif
5443#endif /* HAVE_NTGUI */
5444
5445/* Load PBM image IMG for use on frame F. */
5446
5447static int
5448pbm_load (f, img)
5449 struct frame *f;
5450 struct image *img;
5451{
5452 int raw_p, x, y;
5453 int width, height, max_color_idx = 0;
5454 XImagePtr ximg;
5455 Lisp_Object file, specified_file;
5456 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
5457 struct gcpro gcpro1;
5458 unsigned char *contents = NULL;
5459 unsigned char *end, *p;
5460 int size;
5461
5462 specified_file = image_spec_value (img->spec, QCfile, NULL);
5463 file = Qnil;
5464 GCPRO1 (file);
5465
5466 if (STRINGP (specified_file))
5467 {
5468 file = x_find_image_file (specified_file);
5469 if (!STRINGP (file))
5470 {
5471 image_error ("Cannot find image file `%s'", specified_file, Qnil);
5472 UNGCPRO;
5473 return 0;
5474 }
5475
5476 contents = slurp_file (SDATA (file), &size);
5477 if (contents == NULL)
5478 {
5479 image_error ("Error reading `%s'", file, Qnil);
5480 UNGCPRO;
5481 return 0;
5482 }
5483
5484 p = contents;
5485 end = contents + size;
5486 }
5487 else
5488 {
5489 Lisp_Object data;
5490 data = image_spec_value (img->spec, QCdata, NULL);
5491 p = SDATA (data);
5492 end = p + SBYTES (data);
5493 }
5494
5495 /* Check magic number. */
5496 if (end - p < 2 || *p++ != 'P')
5497 {
5498 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
5499 error:
5500 xfree (contents);
5501 UNGCPRO;
5502 return 0;
5503 }
5504
5505 switch (*p++)
5506 {
5507 case '1':
5508 raw_p = 0, type = PBM_MONO;
5509 break;
5510
5511 case '2':
5512 raw_p = 0, type = PBM_GRAY;
5513 break;
5514
5515 case '3':
5516 raw_p = 0, type = PBM_COLOR;
5517 break;
5518
5519 case '4':
5520 raw_p = 1, type = PBM_MONO;
5521 break;
5522
5523 case '5':
5524 raw_p = 1, type = PBM_GRAY;
5525 break;
5526
5527 case '6':
5528 raw_p = 1, type = PBM_COLOR;
5529 break;
5530
5531 default:
5532 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
5533 goto error;
5534 }
5535
5536 /* Read width, height, maximum color-component. Characters
5537 starting with `#' up to the end of a line are ignored. */
5538 width = pbm_scan_number (&p, end);
5539 height = pbm_scan_number (&p, end);
5540
5541 if (type != PBM_MONO)
5542 {
5543 max_color_idx = pbm_scan_number (&p, end);
b9c89e11
JR
5544 if (max_color_idx > 65535 || max_color_idx < 0)
5545 {
5546 image_error ("Unsupported maximum PBM color value", Qnil, Qnil);
5547 goto error;
5548 }
4ef0d4d0
KS
5549 }
5550
b9c89e11
JR
5551 if (!check_image_size (f, width, height))
5552 {
10ea2b82 5553 image_error ("Invalid image size (see `max-image-size')", Qnil, Qnil);
b9c89e11
JR
5554 goto error;
5555 }
4ef0d4d0
KS
5556
5557 if (!x_create_x_image_and_pixmap (f, width, height, 0,
5558 &ximg, &img->pixmap))
5559 goto error;
5560
5561 /* Initialize the color hash table. */
5562 init_color_table ();
5563
5564 if (type == PBM_MONO)
5565 {
5566 int c = 0, g;
5567 struct image_keyword fmt[PBM_LAST];
5568 unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
5569 unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
5570
5571 /* Parse the image specification. */
5572 bcopy (pbm_format, fmt, sizeof fmt);
5573 parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
5574
5575 /* Get foreground and background colors, maybe allocate colors. */
5576 if (fmt[PBM_FOREGROUND].count
5577 && STRINGP (fmt[PBM_FOREGROUND].value))
5578 fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
5579 if (fmt[PBM_BACKGROUND].count
5580 && STRINGP (fmt[PBM_BACKGROUND].value))
5581 {
5582 bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg);
5583 img->background = bg;
5584 img->background_valid = 1;
5585 }
5586
5587 for (y = 0; y < height; ++y)
5588 for (x = 0; x < width; ++x)
5589 {
5590 if (raw_p)
5591 {
5592 if ((x & 7) == 0)
c295e710
CY
5593 {
5594 if (p >= end)
5595 {
5596 x_destroy_x_image (ximg);
5597 x_clear_image (f, img);
5598 image_error ("Invalid image size in image `%s'",
5599 img->spec, Qnil);
5600 goto error;
5601 }
5602 c = *p++;
5603 }
4ef0d4d0
KS
5604 g = c & 0x80;
5605 c <<= 1;
5606 }
5607 else
5608 g = pbm_scan_number (&p, end);
5609
5610 XPutPixel (ximg, x, y, g ? fg : bg);
5611 }
5612 }
5613 else
5614 {
b9c89e11
JR
5615 int expected_size = height * width;
5616 if (max_color_idx > 255)
5617 expected_size *= 2;
5618 if (type == PBM_COLOR)
5619 expected_size *= 3;
5620
5621 if (raw_p && p + expected_size > end)
39e653ea
CY
5622 {
5623 x_destroy_x_image (ximg);
fb0b0862 5624 x_clear_image (f, img);
39e653ea
CY
5625 image_error ("Invalid image size in image `%s'",
5626 img->spec, Qnil);
5627 goto error;
5628 }
5629
4ef0d4d0
KS
5630 for (y = 0; y < height; ++y)
5631 for (x = 0; x < width; ++x)
5632 {
5633 int r, g, b;
5634
b9c89e11
JR
5635 if (type == PBM_GRAY && raw_p)
5636 {
5637 r = g = b = *p++;
5638 if (max_color_idx > 255)
5639 r = g = b = r * 256 + *p++;
5640 }
5641 else if (type == PBM_GRAY)
5642 r = g = b = pbm_scan_number (&p, end);
4ef0d4d0
KS
5643 else if (raw_p)
5644 {
5645 r = *p++;
b9c89e11
JR
5646 if (max_color_idx > 255)
5647 r = r * 256 + *p++;
4ef0d4d0 5648 g = *p++;
b9c89e11
JR
5649 if (max_color_idx > 255)
5650 g = g * 256 + *p++;
4ef0d4d0 5651 b = *p++;
b9c89e11
JR
5652 if (max_color_idx > 255)
5653 b = b * 256 + *p++;
4ef0d4d0
KS
5654 }
5655 else
5656 {
5657 r = pbm_scan_number (&p, end);
5658 g = pbm_scan_number (&p, end);
5659 b = pbm_scan_number (&p, end);
5660 }
5661
5662 if (r < 0 || g < 0 || b < 0)
5663 {
5664 x_destroy_x_image (ximg);
5665 image_error ("Invalid pixel value in image `%s'",
5666 img->spec, Qnil);
5667 goto error;
5668 }
5669
5670 /* RGB values are now in the range 0..max_color_idx.
5671 Scale this to the range 0..0xffff supported by X. */
5672 r = (double) r * 65535 / max_color_idx;
5673 g = (double) g * 65535 / max_color_idx;
5674 b = (double) b * 65535 / max_color_idx;
5675 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
5676 }
5677 }
5678
5679#ifdef COLOR_TABLE_SUPPORT
5680 /* Store in IMG->colors the colors allocated for the image, and
5681 free the color table. */
5682 img->colors = colors_in_color_table (&img->ncolors);
5683 free_color_table ();
5684#endif /* COLOR_TABLE_SUPPORT */
5685
5686 img->width = width;
5687 img->height = height;
5688
5689 /* Maybe fill in the background field while we have ximg handy. */
5690
5691 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
2e09fef1
EZ
5692 /* Casting avoids a GCC warning. */
5693 IMAGE_BACKGROUND (img, f, (XImagePtr_or_DC)ximg);
4ef0d4d0
KS
5694
5695 /* Put the image into a pixmap. */
5696 x_put_x_image (f, ximg, img->pixmap, width, height);
5697 x_destroy_x_image (ximg);
5698
5699 /* X and W32 versions did it here, MAC version above. ++kfs
1f026899 5700 img->width = width;
4ef0d4d0
KS
5701 img->height = height; */
5702
5703 UNGCPRO;
5704 xfree (contents);
5705 return 1;
5706}
5707
5708\f
5709/***********************************************************************
5710 PNG
5711 ***********************************************************************/
5712
9e2a2647 5713#if defined (HAVE_PNG) || defined (HAVE_NS)
4ef0d4d0
KS
5714
5715/* Function prototypes. */
5716
5717static int png_image_p P_ ((Lisp_Object object));
5718static int png_load P_ ((struct frame *f, struct image *img));
5719
5720/* The symbol `png' identifying images of this type. */
5721
5722Lisp_Object Qpng;
5723
5724/* Indices of image specification fields in png_format, below. */
5725
5726enum png_keyword_index
5727{
5728 PNG_TYPE,
5729 PNG_DATA,
5730 PNG_FILE,
5731 PNG_ASCENT,
5732 PNG_MARGIN,
5733 PNG_RELIEF,
5734 PNG_ALGORITHM,
5735 PNG_HEURISTIC_MASK,
5736 PNG_MASK,
5737 PNG_BACKGROUND,
5738 PNG_LAST
5739};
5740
5741/* Vector of image_keyword structures describing the format
5742 of valid user-defined image specifications. */
5743
5744static struct image_keyword png_format[PNG_LAST] =
5745{
5746 {":type", IMAGE_SYMBOL_VALUE, 1},
5747 {":data", IMAGE_STRING_VALUE, 0},
5748 {":file", IMAGE_STRING_VALUE, 0},
5749 {":ascent", IMAGE_ASCENT_VALUE, 0},
5750 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
5751 {":relief", IMAGE_INTEGER_VALUE, 0},
5752 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5753 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5754 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5755 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
5756};
5757
5758/* Structure describing the image type `png'. */
5759
5760static struct image_type png_type =
5761{
5762 &Qpng,
5763 png_image_p,
5764 png_load,
5765 x_clear_image,
5766 NULL
5767};
5768
5769/* Return non-zero if OBJECT is a valid PNG image specification. */
5770
5771static int
5772png_image_p (object)
5773 Lisp_Object object;
5774{
5775 struct image_keyword fmt[PNG_LAST];
5776 bcopy (png_format, fmt, sizeof fmt);
5777
5778 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng))
5779 return 0;
5780
5781 /* Must specify either the :data or :file keyword. */
5782 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
5783}
5784
9e2a2647 5785#endif /* HAVE_PNG || HAVE_NS */
4ef0d4d0
KS
5786
5787
5788#ifdef HAVE_PNG
5789
5790#if defined HAVE_LIBPNG_PNG_H
5791# include <libpng/png.h>
5792#else
5793# include <png.h>
5794#endif
5795
5796#ifdef HAVE_NTGUI
5797/* PNG library details. */
5798
5799DEF_IMGLIB_FN (png_get_io_ptr);
5800DEF_IMGLIB_FN (png_check_sig);
5801DEF_IMGLIB_FN (png_create_read_struct);
5802DEF_IMGLIB_FN (png_create_info_struct);
5803DEF_IMGLIB_FN (png_destroy_read_struct);
5804DEF_IMGLIB_FN (png_set_read_fn);
4ef0d4d0
KS
5805DEF_IMGLIB_FN (png_set_sig_bytes);
5806DEF_IMGLIB_FN (png_read_info);
5807DEF_IMGLIB_FN (png_get_IHDR);
5808DEF_IMGLIB_FN (png_get_valid);
5809DEF_IMGLIB_FN (png_set_strip_16);
5810DEF_IMGLIB_FN (png_set_expand);
5811DEF_IMGLIB_FN (png_set_gray_to_rgb);
5812DEF_IMGLIB_FN (png_set_background);
5813DEF_IMGLIB_FN (png_get_bKGD);
5814DEF_IMGLIB_FN (png_read_update_info);
5815DEF_IMGLIB_FN (png_get_channels);
5816DEF_IMGLIB_FN (png_get_rowbytes);
5817DEF_IMGLIB_FN (png_read_image);
5818DEF_IMGLIB_FN (png_read_end);
5819DEF_IMGLIB_FN (png_error);
5820
5821static int
0855eb52 5822init_png_functions (Lisp_Object libraries)
4ef0d4d0
KS
5823{
5824 HMODULE library;
5825
4ef0d4d0 5826 /* Try loading libpng under probable names. */
0855eb52 5827 if (!(library = w32_delayed_load (libraries, Qpng)))
4ef0d4d0
KS
5828 return 0;
5829
5830 LOAD_IMGLIB_FN (library, png_get_io_ptr);
5831 LOAD_IMGLIB_FN (library, png_check_sig);
5832 LOAD_IMGLIB_FN (library, png_create_read_struct);
5833 LOAD_IMGLIB_FN (library, png_create_info_struct);
5834 LOAD_IMGLIB_FN (library, png_destroy_read_struct);
5835 LOAD_IMGLIB_FN (library, png_set_read_fn);
4ef0d4d0
KS
5836 LOAD_IMGLIB_FN (library, png_set_sig_bytes);
5837 LOAD_IMGLIB_FN (library, png_read_info);
5838 LOAD_IMGLIB_FN (library, png_get_IHDR);
5839 LOAD_IMGLIB_FN (library, png_get_valid);
5840 LOAD_IMGLIB_FN (library, png_set_strip_16);
5841 LOAD_IMGLIB_FN (library, png_set_expand);
5842 LOAD_IMGLIB_FN (library, png_set_gray_to_rgb);
5843 LOAD_IMGLIB_FN (library, png_set_background);
5844 LOAD_IMGLIB_FN (library, png_get_bKGD);
5845 LOAD_IMGLIB_FN (library, png_read_update_info);
5846 LOAD_IMGLIB_FN (library, png_get_channels);
5847 LOAD_IMGLIB_FN (library, png_get_rowbytes);
5848 LOAD_IMGLIB_FN (library, png_read_image);
5849 LOAD_IMGLIB_FN (library, png_read_end);
5850 LOAD_IMGLIB_FN (library, png_error);
5851 return 1;
5852}
5853#else
5854
5855#define fn_png_get_io_ptr png_get_io_ptr
5856#define fn_png_check_sig png_check_sig
5857#define fn_png_create_read_struct png_create_read_struct
5858#define fn_png_create_info_struct png_create_info_struct
5859#define fn_png_destroy_read_struct png_destroy_read_struct
5860#define fn_png_set_read_fn png_set_read_fn
4ef0d4d0
KS
5861#define fn_png_set_sig_bytes png_set_sig_bytes
5862#define fn_png_read_info png_read_info
5863#define fn_png_get_IHDR png_get_IHDR
5864#define fn_png_get_valid png_get_valid
5865#define fn_png_set_strip_16 png_set_strip_16
5866#define fn_png_set_expand png_set_expand
5867#define fn_png_set_gray_to_rgb png_set_gray_to_rgb
5868#define fn_png_set_background png_set_background
5869#define fn_png_get_bKGD png_get_bKGD
5870#define fn_png_read_update_info png_read_update_info
5871#define fn_png_get_channels png_get_channels
5872#define fn_png_get_rowbytes png_get_rowbytes
5873#define fn_png_read_image png_read_image
5874#define fn_png_read_end png_read_end
5875#define fn_png_error png_error
5876
5877#endif /* HAVE_NTGUI */
5878
5879/* Error and warning handlers installed when the PNG library
5880 is initialized. */
5881
5882static void
5883my_png_error (png_ptr, msg)
5884 png_struct *png_ptr;
5885 char *msg;
5886{
5887 xassert (png_ptr != NULL);
5888 image_error ("PNG error: %s", build_string (msg), Qnil);
5889 longjmp (png_ptr->jmpbuf, 1);
5890}
5891
5892
5893static void
5894my_png_warning (png_ptr, msg)
5895 png_struct *png_ptr;
5896 char *msg;
5897{
5898 xassert (png_ptr != NULL);
5899 image_error ("PNG warning: %s", build_string (msg), Qnil);
5900}
5901
5902/* Memory source for PNG decoding. */
5903
5904struct png_memory_storage
5905{
5906 unsigned char *bytes; /* The data */
5907 size_t len; /* How big is it? */
5908 int index; /* Where are we? */
5909};
5910
5911
5912/* Function set as reader function when reading PNG image from memory.
5913 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
5914 bytes from the input to DATA. */
5915
5916static void
5917png_read_from_memory (png_ptr, data, length)
5918 png_structp png_ptr;
5919 png_bytep data;
5920 png_size_t length;
5921{
5922 struct png_memory_storage *tbr
5923 = (struct png_memory_storage *) fn_png_get_io_ptr (png_ptr);
5924
5925 if (length > tbr->len - tbr->index)
5926 fn_png_error (png_ptr, "Read error");
5927
5928 bcopy (tbr->bytes + tbr->index, data, length);
5929 tbr->index = tbr->index + length;
5930}
5931
b0da69a7 5932
9a22a004
JB
5933/* Function set as reader function when reading PNG image from a file.
5934 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
5935 bytes from the input to DATA. */
5936
5937static void
5938png_read_from_file (png_ptr, data, length)
5939 png_structp png_ptr;
5940 png_bytep data;
5941 png_size_t length;
5942{
5943 FILE *fp = (FILE *) fn_png_get_io_ptr (png_ptr);
5944
5945 if (fread (data, 1, length, fp) < length)
5946 fn_png_error (png_ptr, "Read error");
5947}
5948
5949
4ef0d4d0
KS
5950/* Load PNG image IMG for use on frame F. Value is non-zero if
5951 successful. */
5952
5953static int
5954png_load (f, img)
5955 struct frame *f;
5956 struct image *img;
5957{
5958 Lisp_Object file, specified_file;
5959 Lisp_Object specified_data;
5960 int x, y, i;
5961 XImagePtr ximg, mask_img = NULL;
5962 struct gcpro gcpro1;
5963 png_struct *png_ptr = NULL;
5964 png_info *info_ptr = NULL, *end_info = NULL;
5965 FILE *volatile fp = NULL;
5966 png_byte sig[8];
5967 png_byte * volatile pixels = NULL;
5968 png_byte ** volatile rows = NULL;
5969 png_uint_32 width, height;
5970 int bit_depth, color_type, interlace_type;
5971 png_byte channels;
5972 png_uint_32 row_bytes;
5973 int transparent_p;
4ef0d4d0
KS
5974 struct png_memory_storage tbr; /* Data to be read */
5975
5976 /* Find out what file to load. */
5977 specified_file = image_spec_value (img->spec, QCfile, NULL);
5978 specified_data = image_spec_value (img->spec, QCdata, NULL);
5979 file = Qnil;
5980 GCPRO1 (file);
5981
5982 if (NILP (specified_data))
5983 {
5984 file = x_find_image_file (specified_file);
5985 if (!STRINGP (file))
5986 {
5987 image_error ("Cannot find image file `%s'", specified_file, Qnil);
5988 UNGCPRO;
5989 return 0;
5990 }
5991
5992 /* Open the image file. */
5993 fp = fopen (SDATA (file), "rb");
5994 if (!fp)
5995 {
5996 image_error ("Cannot open image file `%s'", file, Qnil);
5997 UNGCPRO;
4ef0d4d0
KS
5998 return 0;
5999 }
6000
6001 /* Check PNG signature. */
6002 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
6003 || !fn_png_check_sig (sig, sizeof sig))
6004 {
6005 image_error ("Not a PNG file: `%s'", file, Qnil);
6006 UNGCPRO;
6007 fclose (fp);
6008 return 0;
6009 }
6010 }
6011 else
6012 {
6013 /* Read from memory. */
6014 tbr.bytes = SDATA (specified_data);
6015 tbr.len = SBYTES (specified_data);
6016 tbr.index = 0;
6017
6018 /* Check PNG signature. */
6019 if (tbr.len < sizeof sig
6020 || !fn_png_check_sig (tbr.bytes, sizeof sig))
6021 {
6022 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
6023 UNGCPRO;
6024 return 0;
6025 }
6026
6027 /* Need to skip past the signature. */
6028 tbr.bytes += sizeof (sig);
6029 }
6030
2e09fef1
EZ
6031 /* Initialize read and info structs for PNG lib. Casting return
6032 value avoids a GCC warning on W32. */
6033 png_ptr = (png_structp)fn_png_create_read_struct (PNG_LIBPNG_VER_STRING,
6034 NULL, my_png_error,
6035 my_png_warning);
4ef0d4d0
KS
6036 if (!png_ptr)
6037 {
6038 if (fp) fclose (fp);
6039 UNGCPRO;
6040 return 0;
6041 }
6042
2e09fef1
EZ
6043 /* Casting return value avoids a GCC warning on W32. */
6044 info_ptr = (png_infop)fn_png_create_info_struct (png_ptr);
4ef0d4d0
KS
6045 if (!info_ptr)
6046 {
6047 fn_png_destroy_read_struct (&png_ptr, NULL, NULL);
6048 if (fp) fclose (fp);
6049 UNGCPRO;
6050 return 0;
6051 }
6052
2e09fef1
EZ
6053 /* Casting return value avoids a GCC warning on W32. */
6054 end_info = (png_infop)fn_png_create_info_struct (png_ptr);
4ef0d4d0
KS
6055 if (!end_info)
6056 {
6057 fn_png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
6058 if (fp) fclose (fp);
6059 UNGCPRO;
6060 return 0;
6061 }
6062
6063 /* Set error jump-back. We come back here when the PNG library
6064 detects an error. */
6065 if (setjmp (png_ptr->jmpbuf))
6066 {
6067 error:
6068 if (png_ptr)
6069 fn_png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
6070 xfree (pixels);
6071 xfree (rows);
6072 if (fp) fclose (fp);
6073 UNGCPRO;
6074 return 0;
6075 }
6076
6077 /* Read image info. */
6078 if (!NILP (specified_data))
6079 fn_png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
6080 else
9a22a004 6081 fn_png_set_read_fn (png_ptr, (void *) fp, png_read_from_file);
4ef0d4d0
KS
6082
6083 fn_png_set_sig_bytes (png_ptr, sizeof sig);
6084 fn_png_read_info (png_ptr, info_ptr);
6085 fn_png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
6086 &interlace_type, NULL, NULL);
6087
f1f25b99 6088 if (!check_image_size (f, width, height))
10ea2b82
JR
6089 {
6090 image_error ("Invalid image size (see `max-image-size')", Qnil, Qnil);
6091 goto error;
6092 }
4ef0d4d0
KS
6093 /* If image contains simply transparency data, we prefer to
6094 construct a clipping mask. */
6095 if (fn_png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
6096 transparent_p = 1;
6097 else
6098 transparent_p = 0;
6099
6100 /* This function is easier to write if we only have to handle
6101 one data format: RGB or RGBA with 8 bits per channel. Let's
6102 transform other formats into that format. */
6103
6104 /* Strip more than 8 bits per channel. */
6105 if (bit_depth == 16)
6106 fn_png_set_strip_16 (png_ptr);
6107
6108 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
6109 if available. */
6110 fn_png_set_expand (png_ptr);
6111
6112 /* Convert grayscale images to RGB. */
6113 if (color_type == PNG_COLOR_TYPE_GRAY
6114 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
6115 fn_png_set_gray_to_rgb (png_ptr);
6116
4ef0d4d0
KS
6117 /* Handle alpha channel by combining the image with a background
6118 color. Do this only if a real alpha channel is supplied. For
6119 simple transparency, we prefer a clipping mask. */
6120 if (!transparent_p)
6121 {
917ac1a9 6122 /* png_color_16 *image_bg; */
4ef0d4d0
KS
6123 Lisp_Object specified_bg
6124 = image_spec_value (img->spec, QCbackground, NULL);
c4f13f44 6125 int shift = (bit_depth == 16) ? 0 : 8;
4ef0d4d0
KS
6126
6127 if (STRINGP (specified_bg))
6128 /* The user specified `:background', use that. */
6129 {
4ef0d4d0
KS
6130 XColor color;
6131 if (x_defined_color (f, SDATA (specified_bg), &color, 0))
6132 {
6133 png_color_16 user_bg;
6134
6135 bzero (&user_bg, sizeof user_bg);
c4f13f44
CY
6136 user_bg.red = color.red >> shift;
6137 user_bg.green = color.green >> shift;
6138 user_bg.blue = color.blue >> shift;
4ef0d4d0
KS
6139
6140 fn_png_set_background (png_ptr, &user_bg,
6141 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
6142 }
6143 }
4ef0d4d0
KS
6144 else
6145 {
c4f13f44
CY
6146 /* We use the current frame background, ignoring any default
6147 background color set by the image. */
8b7d0a16 6148#if defined (HAVE_X_WINDOWS) || defined (HAVE_NTGUI)
4ef0d4d0
KS
6149 XColor color;
6150 png_color_16 frame_background;
6151
6152 color.pixel = FRAME_BACKGROUND_PIXEL (f);
6153 x_query_color (f, &color);
6154
6155 bzero (&frame_background, sizeof frame_background);
c4f13f44
CY
6156 frame_background.red = color.red >> shift;
6157 frame_background.green = color.green >> shift;
6158 frame_background.blue = color.blue >> shift;
4ef0d4d0
KS
6159#endif /* HAVE_X_WINDOWS */
6160
4ef0d4d0
KS
6161 fn_png_set_background (png_ptr, &frame_background,
6162 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
6163 }
6164 }
6165
6166 /* Update info structure. */
6167 fn_png_read_update_info (png_ptr, info_ptr);
6168
6169 /* Get number of channels. Valid values are 1 for grayscale images
6170 and images with a palette, 2 for grayscale images with transparency
6171 information (alpha channel), 3 for RGB images, and 4 for RGB
6172 images with alpha channel, i.e. RGBA. If conversions above were
6173 sufficient we should only have 3 or 4 channels here. */
6174 channels = fn_png_get_channels (png_ptr, info_ptr);
6175 xassert (channels == 3 || channels == 4);
6176
6177 /* Number of bytes needed for one row of the image. */
6178 row_bytes = fn_png_get_rowbytes (png_ptr, info_ptr);
6179
6180 /* Allocate memory for the image. */
6181 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
6182 rows = (png_byte **) xmalloc (height * sizeof *rows);
6183 for (i = 0; i < height; ++i)
6184 rows[i] = pixels + i * row_bytes;
6185
6186 /* Read the entire image. */
6187 fn_png_read_image (png_ptr, rows);
6188 fn_png_read_end (png_ptr, info_ptr);
6189 if (fp)
6190 {
6191 fclose (fp);
6192 fp = NULL;
6193 }
6194
6195 /* Create the X image and pixmap. */
6196 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
6197 &img->pixmap))
6198 goto error;
6199
6200 /* Create an image and pixmap serving as mask if the PNG image
6201 contains an alpha channel. */
6202 if (channels == 4
6203 && !transparent_p
6204 && !x_create_x_image_and_pixmap (f, width, height, 1,
6205 &mask_img, &img->mask))
6206 {
6207 x_destroy_x_image (ximg);
6208 Free_Pixmap (FRAME_X_DISPLAY (f), img->pixmap);
6209 img->pixmap = NO_PIXMAP;
6210 goto error;
6211 }
6212
6213 /* Fill the X image and mask from PNG data. */
6214 init_color_table ();
6215
6216 for (y = 0; y < height; ++y)
6217 {
6218 png_byte *p = rows[y];
6219
6220 for (x = 0; x < width; ++x)
6221 {
6222 unsigned r, g, b;
6223
6224 r = *p++ << 8;
6225 g = *p++ << 8;
6226 b = *p++ << 8;
6227 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
6228 /* An alpha channel, aka mask channel, associates variable
6229 transparency with an image. Where other image formats
6230 support binary transparency---fully transparent or fully
6231 opaque---PNG allows up to 254 levels of partial transparency.
6232 The PNG library implements partial transparency by combining
6233 the image with a specified background color.
6234
6235 I'm not sure how to handle this here nicely: because the
6236 background on which the image is displayed may change, for
6237 real alpha channel support, it would be necessary to create
6238 a new image for each possible background.
6239
6240 What I'm doing now is that a mask is created if we have
6241 boolean transparency information. Otherwise I'm using
6242 the frame's background color to combine the image with. */
6243
6244 if (channels == 4)
6245 {
6246 if (mask_img)
9ecf6403 6247 XPutPixel (mask_img, x, y, *p > 0 ? PIX_MASK_DRAW : PIX_MASK_RETAIN);
4ef0d4d0
KS
6248 ++p;
6249 }
6250 }
6251 }
6252
6253 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
6254 /* Set IMG's background color from the PNG image, unless the user
6255 overrode it. */
6256 {
6257 png_color_16 *bg;
6258 if (fn_png_get_bKGD (png_ptr, info_ptr, &bg))
6259 {
6260 img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue);
6261 img->background_valid = 1;
6262 }
6263 }
6264
6265#ifdef COLOR_TABLE_SUPPORT
6266 /* Remember colors allocated for this image. */
6267 img->colors = colors_in_color_table (&img->ncolors);
6268 free_color_table ();
6269#endif /* COLOR_TABLE_SUPPORT */
6270
6271 /* Clean up. */
6272 fn_png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
6273 xfree (rows);
6274 xfree (pixels);
6275
6276 img->width = width;
6277 img->height = height;
6278
2e09fef1
EZ
6279 /* Maybe fill in the background field while we have ximg handy.
6280 Casting avoids a GCC warning. */
6281 IMAGE_BACKGROUND (img, f, (XImagePtr_or_DC)ximg);
4ef0d4d0
KS
6282
6283 /* Put the image into the pixmap, then free the X image and its buffer. */
6284 x_put_x_image (f, ximg, img->pixmap, width, height);
6285 x_destroy_x_image (ximg);
6286
6287 /* Same for the mask. */
6288 if (mask_img)
6289 {
2e09fef1
EZ
6290 /* Fill in the background_transparent field while we have the
6291 mask handy. Casting avoids a GCC warning. */
6292 image_background_transparent (img, f, (XImagePtr_or_DC)mask_img);
4ef0d4d0
KS
6293
6294 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
6295 x_destroy_x_image (mask_img);
6296 }
6297
6298 UNGCPRO;
6299 return 1;
6300}
6301
6302#else /* HAVE_PNG */
6303
edfda783
AR
6304#ifdef HAVE_NS
6305static int
6306png_load (struct frame *f, struct image *img)
6307{
6308 return ns_load_image(f, img,
6309 image_spec_value (img->spec, QCfile, NULL),
6310 image_spec_value (img->spec, QCdata, NULL));
6311}
6312#endif /* HAVE_NS */
6313
6314
4ef0d4d0
KS
6315#endif /* !HAVE_PNG */
6316
6317
6318\f
6319/***********************************************************************
6320 JPEG
6321 ***********************************************************************/
6322
9e2a2647 6323#if defined (HAVE_JPEG) || defined (HAVE_NS)
4ef0d4d0
KS
6324
6325static int jpeg_image_p P_ ((Lisp_Object object));
6326static int jpeg_load P_ ((struct frame *f, struct image *img));
6327
6328/* The symbol `jpeg' identifying images of this type. */
6329
6330Lisp_Object Qjpeg;
6331
6332/* Indices of image specification fields in gs_format, below. */
6333
6334enum jpeg_keyword_index
6335{
6336 JPEG_TYPE,
6337 JPEG_DATA,
6338 JPEG_FILE,
6339 JPEG_ASCENT,
6340 JPEG_MARGIN,
6341 JPEG_RELIEF,
6342 JPEG_ALGORITHM,
6343 JPEG_HEURISTIC_MASK,
6344 JPEG_MASK,
6345 JPEG_BACKGROUND,
6346 JPEG_LAST
6347};
6348
6349/* Vector of image_keyword structures describing the format
6350 of valid user-defined image specifications. */
6351
6352static struct image_keyword jpeg_format[JPEG_LAST] =
6353{
6354 {":type", IMAGE_SYMBOL_VALUE, 1},
6355 {":data", IMAGE_STRING_VALUE, 0},
6356 {":file", IMAGE_STRING_VALUE, 0},
6357 {":ascent", IMAGE_ASCENT_VALUE, 0},
6358 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6359 {":relief", IMAGE_INTEGER_VALUE, 0},
6360 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6361 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6362 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6363 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6364};
6365
6366/* Structure describing the image type `jpeg'. */
6367
6368static struct image_type jpeg_type =
6369{
6370 &Qjpeg,
6371 jpeg_image_p,
6372 jpeg_load,
6373 x_clear_image,
6374 NULL
6375};
6376
6377/* Return non-zero if OBJECT is a valid JPEG image specification. */
6378
6379static int
6380jpeg_image_p (object)
6381 Lisp_Object object;
6382{
6383 struct image_keyword fmt[JPEG_LAST];
6384
6385 bcopy (jpeg_format, fmt, sizeof fmt);
6386
6387 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg))
6388 return 0;
6389
6390 /* Must specify either the :data or :file keyword. */
6391 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
6392}
6393
9e2a2647 6394#endif /* HAVE_JPEG || HAVE_NS */
4ef0d4d0
KS
6395
6396#ifdef HAVE_JPEG
6397
6398/* Work around a warning about HAVE_STDLIB_H being redefined in
6399 jconfig.h. */
6400#ifdef HAVE_STDLIB_H
6401#define HAVE_STDLIB_H_1
6402#undef HAVE_STDLIB_H
6403#endif /* HAVE_STLIB_H */
6404
66354420 6405#if defined (HAVE_NTGUI) && !defined (__WIN32__)
28893db2
JB
6406/* In older releases of the jpeg library, jpeglib.h will define boolean
6407 differently depending on __WIN32__, so make sure it is defined. */
66354420
JR
6408#define __WIN32__ 1
6409#endif
6410
4ef0d4d0
KS
6411#include <jpeglib.h>
6412#include <jerror.h>
6413#include <setjmp.h>
6414
6415#ifdef HAVE_STLIB_H_1
6416#define HAVE_STDLIB_H 1
6417#endif
6418
6419#ifdef HAVE_NTGUI
6420
6421/* JPEG library details. */
6422DEF_IMGLIB_FN (jpeg_CreateDecompress);
6423DEF_IMGLIB_FN (jpeg_start_decompress);
6424DEF_IMGLIB_FN (jpeg_finish_decompress);
6425DEF_IMGLIB_FN (jpeg_destroy_decompress);
6426DEF_IMGLIB_FN (jpeg_read_header);
6427DEF_IMGLIB_FN (jpeg_read_scanlines);
4ef0d4d0
KS
6428DEF_IMGLIB_FN (jpeg_std_error);
6429DEF_IMGLIB_FN (jpeg_resync_to_restart);
6430
6431static int
0855eb52 6432init_jpeg_functions (Lisp_Object libraries)
4ef0d4d0
KS
6433{
6434 HMODULE library;
6435
0855eb52 6436 if (!(library = w32_delayed_load (libraries, Qjpeg)))
4ef0d4d0
KS
6437 return 0;
6438
6439 LOAD_IMGLIB_FN (library, jpeg_finish_decompress);
6440 LOAD_IMGLIB_FN (library, jpeg_read_scanlines);
6441 LOAD_IMGLIB_FN (library, jpeg_start_decompress);
6442 LOAD_IMGLIB_FN (library, jpeg_read_header);
4ef0d4d0
KS
6443 LOAD_IMGLIB_FN (library, jpeg_CreateDecompress);
6444 LOAD_IMGLIB_FN (library, jpeg_destroy_decompress);
6445 LOAD_IMGLIB_FN (library, jpeg_std_error);
6446 LOAD_IMGLIB_FN (library, jpeg_resync_to_restart);
6447 return 1;
6448}
6449
6450/* Wrapper since we can't directly assign the function pointer
6451 to another function pointer that was declared more completely easily. */
6452static boolean
5fc9fdeb 6453jpeg_resync_to_restart_wrapper (cinfo, desired)
4ef0d4d0
KS
6454 j_decompress_ptr cinfo;
6455 int desired;
6456{
6457 return fn_jpeg_resync_to_restart (cinfo, desired);
6458}
6459
6460#else
6461
6462#define fn_jpeg_CreateDecompress(a,b,c) jpeg_create_decompress(a)
6463#define fn_jpeg_start_decompress jpeg_start_decompress
6464#define fn_jpeg_finish_decompress jpeg_finish_decompress
6465#define fn_jpeg_destroy_decompress jpeg_destroy_decompress
6466#define fn_jpeg_read_header jpeg_read_header
6467#define fn_jpeg_read_scanlines jpeg_read_scanlines
4ef0d4d0
KS
6468#define fn_jpeg_std_error jpeg_std_error
6469#define jpeg_resync_to_restart_wrapper jpeg_resync_to_restart
6470
6471#endif /* HAVE_NTGUI */
6472
6473struct my_jpeg_error_mgr
6474{
6475 struct jpeg_error_mgr pub;
6476 jmp_buf setjmp_buffer;
6477};
6478
6479
6480static void
6481my_error_exit (cinfo)
6482 j_common_ptr cinfo;
6483{
6484 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
6485 longjmp (mgr->setjmp_buffer, 1);
6486}
6487
6488
6489/* Init source method for JPEG data source manager. Called by
6490 jpeg_read_header() before any data is actually read. See
6491 libjpeg.doc from the JPEG lib distribution. */
6492
6493static void
b25a72ab
JB
6494our_common_init_source (cinfo)
6495 j_decompress_ptr cinfo;
6496{
6497}
6498
6499
6500/* Method to terminate data source. Called by
6501 jpeg_finish_decompress() after all data has been processed. */
6502
6503static void
6504our_common_term_source (cinfo)
4ef0d4d0
KS
6505 j_decompress_ptr cinfo;
6506{
6507}
6508
6509
6510/* Fill input buffer method for JPEG data source manager. Called
6511 whenever more data is needed. We read the whole image in one step,
6512 so this only adds a fake end of input marker at the end. */
6513
5a1539f3 6514static JOCTET our_memory_buffer[2];
aca946f3 6515
4ef0d4d0 6516static boolean
b25a72ab 6517our_memory_fill_input_buffer (cinfo)
4ef0d4d0
KS
6518 j_decompress_ptr cinfo;
6519{
6520 /* Insert a fake EOI marker. */
6521 struct jpeg_source_mgr *src = cinfo->src;
4ef0d4d0 6522
5a1539f3
MB
6523 our_memory_buffer[0] = (JOCTET) 0xFF;
6524 our_memory_buffer[1] = (JOCTET) JPEG_EOI;
4ef0d4d0 6525
5a1539f3 6526 src->next_input_byte = our_memory_buffer;
4ef0d4d0 6527 src->bytes_in_buffer = 2;
e0e30823 6528 return 1;
4ef0d4d0
KS
6529}
6530
6531
6532/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
6533 is the JPEG data source manager. */
6534
6535static void
b25a72ab 6536our_memory_skip_input_data (cinfo, num_bytes)
4ef0d4d0
KS
6537 j_decompress_ptr cinfo;
6538 long num_bytes;
6539{
6540 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
6541
6542 if (src)
6543 {
6544 if (num_bytes > src->bytes_in_buffer)
6545 ERREXIT (cinfo, JERR_INPUT_EOF);
6546
6547 src->bytes_in_buffer -= num_bytes;
6548 src->next_input_byte += num_bytes;
6549 }
6550}
6551
6552
4ef0d4d0
KS
6553/* Set up the JPEG lib for reading an image from DATA which contains
6554 LEN bytes. CINFO is the decompression info structure created for
6555 reading the image. */
6556
6557static void
6558jpeg_memory_src (cinfo, data, len)
6559 j_decompress_ptr cinfo;
6560 JOCTET *data;
6561 unsigned int len;
6562{
6563 struct jpeg_source_mgr *src;
6564
6565 if (cinfo->src == NULL)
6566 {
6567 /* First time for this JPEG object? */
6568 cinfo->src = (struct jpeg_source_mgr *)
6569 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
6570 sizeof (struct jpeg_source_mgr));
6571 src = (struct jpeg_source_mgr *) cinfo->src;
6572 src->next_input_byte = data;
6573 }
6574
6575 src = (struct jpeg_source_mgr *) cinfo->src;
b25a72ab
JB
6576 src->init_source = our_common_init_source;
6577 src->fill_input_buffer = our_memory_fill_input_buffer;
6578 src->skip_input_data = our_memory_skip_input_data;
4ef0d4d0 6579 src->resync_to_restart = jpeg_resync_to_restart_wrapper; /* Use default method. */
b25a72ab 6580 src->term_source = our_common_term_source;
4ef0d4d0
KS
6581 src->bytes_in_buffer = len;
6582 src->next_input_byte = data;
6583}
6584
6585
b25a72ab
JB
6586struct jpeg_stdio_mgr
6587{
6588 struct jpeg_source_mgr mgr;
6589 boolean finished;
6590 FILE *file;
6591 JOCTET *buffer;
6592};
6593
6594
6595/* Size of buffer to read JPEG from file.
6596 Not too big, as we want to use alloc_small. */
6597#define JPEG_STDIO_BUFFER_SIZE 8192
6598
6599
6600/* Fill input buffer method for JPEG data source manager. Called
6601 whenever more data is needed. The data is read from a FILE *. */
6602
6603static boolean
6604our_stdio_fill_input_buffer (cinfo)
6605 j_decompress_ptr cinfo;
6606{
6607 struct jpeg_stdio_mgr *src;
6608
6609 src = (struct jpeg_stdio_mgr *) cinfo->src;
6610 if (!src->finished)
6611 {
6612 size_t bytes;
6613
6614 bytes = fread (src->buffer, 1, JPEG_STDIO_BUFFER_SIZE, src->file);
6615 if (bytes > 0)
6616 src->mgr.bytes_in_buffer = bytes;
6617 else
6618 {
6619 WARNMS (cinfo, JWRN_JPEG_EOF);
6620 src->finished = 1;
6621 src->buffer[0] = (JOCTET) 0xFF;
6622 src->buffer[1] = (JOCTET) JPEG_EOI;
6623 src->mgr.bytes_in_buffer = 2;
6624 }
6625 src->mgr.next_input_byte = src->buffer;
6626 }
6627
6628 return 1;
6629}
6630
6631
6632/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
6633 is the JPEG data source manager. */
6634
6635static void
6636our_stdio_skip_input_data (cinfo, num_bytes)
6637 j_decompress_ptr cinfo;
6638 long num_bytes;
6639{
6640 struct jpeg_stdio_mgr *src;
6641 src = (struct jpeg_stdio_mgr *) cinfo->src;
6642
6643 while (num_bytes > 0 && !src->finished)
6644 {
6645 if (num_bytes <= src->mgr.bytes_in_buffer)
6646 {
6647 src->mgr.bytes_in_buffer -= num_bytes;
6648 src->mgr.next_input_byte += num_bytes;
6649 break;
6650 }
6651 else
6652 {
6653 num_bytes -= src->mgr.bytes_in_buffer;
6654 src->mgr.bytes_in_buffer = 0;
6655 src->mgr.next_input_byte = NULL;
6656
6657 our_stdio_fill_input_buffer (cinfo);
6658 }
6659 }
6660}
6661
6662
6663/* Set up the JPEG lib for reading an image from a FILE *.
6664 CINFO is the decompression info structure created for
6665 reading the image. */
6666
6667static void
6668jpeg_file_src (cinfo, fp)
6669 j_decompress_ptr cinfo;
6670 FILE *fp;
6671{
6672 struct jpeg_stdio_mgr *src;
6673
6674 if (cinfo->src != NULL)
6675 src = (struct jpeg_stdio_mgr *) cinfo->src;
6676 else
6677 {
6678 /* First time for this JPEG object? */
6679 cinfo->src = (struct jpeg_source_mgr *)
6680 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
6681 sizeof (struct jpeg_stdio_mgr));
6682 src = (struct jpeg_stdio_mgr *) cinfo->src;
6683 src->buffer = (JOCTET *)
6684 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
6685 JPEG_STDIO_BUFFER_SIZE);
6686 }
6687
6688 src->file = fp;
6689 src->finished = 0;
6690 src->mgr.init_source = our_common_init_source;
6691 src->mgr.fill_input_buffer = our_stdio_fill_input_buffer;
6692 src->mgr.skip_input_data = our_stdio_skip_input_data;
6693 src->mgr.resync_to_restart = jpeg_resync_to_restart_wrapper; /* Use default method. */
6694 src->mgr.term_source = our_common_term_source;
6695 src->mgr.bytes_in_buffer = 0;
6696 src->mgr.next_input_byte = NULL;
6697}
6698
6699
4ef0d4d0
KS
6700/* Load image IMG for use on frame F. Patterned after example.c
6701 from the JPEG lib. */
6702
6703static int
6704jpeg_load (f, img)
6705 struct frame *f;
6706 struct image *img;
6707{
6708 struct jpeg_decompress_struct cinfo;
6709 struct my_jpeg_error_mgr mgr;
6710 Lisp_Object file, specified_file;
6711 Lisp_Object specified_data;
6712 FILE * volatile fp = NULL;
6713 JSAMPARRAY buffer;
6714 int row_stride, x, y;
6715 XImagePtr ximg = NULL;
6716 int rc;
6717 unsigned long *colors;
6718 int width, height;
6719 struct gcpro gcpro1;
6720
6721 /* Open the JPEG file. */
6722 specified_file = image_spec_value (img->spec, QCfile, NULL);
6723 specified_data = image_spec_value (img->spec, QCdata, NULL);
6724 file = Qnil;
6725 GCPRO1 (file);
6726
6727 if (NILP (specified_data))
6728 {
6729 file = x_find_image_file (specified_file);
6730 if (!STRINGP (file))
6731 {
6732 image_error ("Cannot find image file `%s'", specified_file, Qnil);
6733 UNGCPRO;
6734 return 0;
6735 }
6736
6737 fp = fopen (SDATA (file), "rb");
6738 if (fp == NULL)
6739 {
6740 image_error ("Cannot open `%s'", file, Qnil);
6741 UNGCPRO;
6742 return 0;
6743 }
6744 }
6745
6746 /* Customize libjpeg's error handling to call my_error_exit when an
2e09fef1
EZ
6747 error is detected. This function will perform a longjmp.
6748 Casting return value avoids a GCC warning on W32. */
6749 cinfo.err = (struct jpeg_error_mgr *)fn_jpeg_std_error (&mgr.pub);
4ef0d4d0
KS
6750 mgr.pub.error_exit = my_error_exit;
6751
6752 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
6753 {
6754 if (rc == 1)
6755 {
6756 /* Called from my_error_exit. Display a JPEG error. */
6757 char buffer[JMSG_LENGTH_MAX];
6758 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
6759 image_error ("Error reading JPEG image `%s': %s", img->spec,
6760 build_string (buffer));
6761 }
6762
6763 /* Close the input file and destroy the JPEG object. */
6764 if (fp)
6765 fclose ((FILE *) fp);
6766 fn_jpeg_destroy_decompress (&cinfo);
6767
6768 /* If we already have an XImage, free that. */
6769 x_destroy_x_image (ximg);
6770
6771 /* Free pixmap and colors. */
6772 x_clear_image (f, img);
6773
6774 UNGCPRO;
6775 return 0;
6776 }
6777
6778 /* Create the JPEG decompression object. Let it read from fp.
6779 Read the JPEG image header. */
6780 fn_jpeg_CreateDecompress (&cinfo, JPEG_LIB_VERSION, sizeof (cinfo));
6781
6782 if (NILP (specified_data))
b25a72ab 6783 jpeg_file_src (&cinfo, (FILE *) fp);
4ef0d4d0
KS
6784 else
6785 jpeg_memory_src (&cinfo, SDATA (specified_data),
6786 SBYTES (specified_data));
6787
e0e30823 6788 fn_jpeg_read_header (&cinfo, 1);
4ef0d4d0
KS
6789
6790 /* Customize decompression so that color quantization will be used.
6791 Start decompression. */
e0e30823 6792 cinfo.quantize_colors = 1;
4ef0d4d0
KS
6793 fn_jpeg_start_decompress (&cinfo);
6794 width = img->width = cinfo.output_width;
6795 height = img->height = cinfo.output_height;
6796
f1f25b99
CY
6797 if (!check_image_size (f, width, height))
6798 {
10ea2b82 6799 image_error ("Invalid image size (see `max-image-size')", Qnil, Qnil);
f1f25b99
CY
6800 longjmp (mgr.setjmp_buffer, 2);
6801 }
6802
4ef0d4d0
KS
6803 /* Create X image and pixmap. */
6804 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
6805 longjmp (mgr.setjmp_buffer, 2);
6806
6807 /* Allocate colors. When color quantization is used,
6808 cinfo.actual_number_of_colors has been set with the number of
6809 colors generated, and cinfo.colormap is a two-dimensional array
6810 of color indices in the range 0..cinfo.actual_number_of_colors.
6811 No more than 255 colors will be generated. */
6812 {
6813 int i, ir, ig, ib;
6814
6815 if (cinfo.out_color_components > 2)
6816 ir = 0, ig = 1, ib = 2;
6817 else if (cinfo.out_color_components > 1)
6818 ir = 0, ig = 1, ib = 0;
6819 else
6820 ir = 0, ig = 0, ib = 0;
6821
6822 /* Use the color table mechanism because it handles colors that
6823 cannot be allocated nicely. Such colors will be replaced with
6824 a default color, and we don't have to care about which colors
6825 can be freed safely, and which can't. */
6826 init_color_table ();
6827 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
6828 * sizeof *colors);
6829
6830 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
6831 {
6832 /* Multiply RGB values with 255 because X expects RGB values
6833 in the range 0..0xffff. */
6834 int r = cinfo.colormap[ir][i] << 8;
6835 int g = cinfo.colormap[ig][i] << 8;
6836 int b = cinfo.colormap[ib][i] << 8;
6837 colors[i] = lookup_rgb_color (f, r, g, b);
6838 }
6839
6840#ifdef COLOR_TABLE_SUPPORT
6841 /* Remember those colors actually allocated. */
6842 img->colors = colors_in_color_table (&img->ncolors);
6843 free_color_table ();
6844#endif /* COLOR_TABLE_SUPPORT */
6845 }
6846
6847 /* Read pixels. */
6848 row_stride = width * cinfo.output_components;
6849 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
6850 row_stride, 1);
6851 for (y = 0; y < height; ++y)
6852 {
6853 fn_jpeg_read_scanlines (&cinfo, buffer, 1);
6854 for (x = 0; x < cinfo.output_width; ++x)
6855 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
6856 }
6857
6858 /* Clean up. */
6859 fn_jpeg_finish_decompress (&cinfo);
6860 fn_jpeg_destroy_decompress (&cinfo);
6861 if (fp)
6862 fclose ((FILE *) fp);
6863
6864 /* Maybe fill in the background field while we have ximg handy. */
6865 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
2e09fef1
EZ
6866 /* Casting avoids a GCC warning. */
6867 IMAGE_BACKGROUND (img, f, (XImagePtr_or_DC)ximg);
4ef0d4d0
KS
6868
6869 /* Put the image into the pixmap. */
6870 x_put_x_image (f, ximg, img->pixmap, width, height);
6871 x_destroy_x_image (ximg);
6872 UNGCPRO;
6873 return 1;
6874}
6875
6876#else /* HAVE_JPEG */
6877
edfda783
AR
6878#ifdef HAVE_NS
6879static int
6880jpeg_load (struct frame *f, struct image *img)
6881{
6882 return ns_load_image(f, img,
6883 image_spec_value (img->spec, QCfile, NULL),
6884 image_spec_value (img->spec, QCdata, NULL));
6885}
6886#endif /* HAVE_NS */
6887
4ef0d4d0
KS
6888#endif /* !HAVE_JPEG */
6889
6890
6891\f
6892/***********************************************************************
6893 TIFF
6894 ***********************************************************************/
6895
9e2a2647 6896#if defined (HAVE_TIFF) || defined (HAVE_NS)
4ef0d4d0
KS
6897
6898static int tiff_image_p P_ ((Lisp_Object object));
6899static int tiff_load P_ ((struct frame *f, struct image *img));
6900
6901/* The symbol `tiff' identifying images of this type. */
6902
6903Lisp_Object Qtiff;
6904
6905/* Indices of image specification fields in tiff_format, below. */
6906
6907enum tiff_keyword_index
6908{
6909 TIFF_TYPE,
6910 TIFF_DATA,
6911 TIFF_FILE,
6912 TIFF_ASCENT,
6913 TIFF_MARGIN,
6914 TIFF_RELIEF,
6915 TIFF_ALGORITHM,
6916 TIFF_HEURISTIC_MASK,
6917 TIFF_MASK,
6918 TIFF_BACKGROUND,
58279503 6919 TIFF_INDEX,
4ef0d4d0
KS
6920 TIFF_LAST
6921};
6922
6923/* Vector of image_keyword structures describing the format
6924 of valid user-defined image specifications. */
6925
6926static struct image_keyword tiff_format[TIFF_LAST] =
6927{
6928 {":type", IMAGE_SYMBOL_VALUE, 1},
6929 {":data", IMAGE_STRING_VALUE, 0},
6930 {":file", IMAGE_STRING_VALUE, 0},
6931 {":ascent", IMAGE_ASCENT_VALUE, 0},
6932 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6933 {":relief", IMAGE_INTEGER_VALUE, 0},
6934 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6935 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6936 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
58279503
JR
6937 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
6938 {":index", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}
4ef0d4d0
KS
6939};
6940
6941/* Structure describing the image type `tiff'. */
6942
6943static struct image_type tiff_type =
6944{
6945 &Qtiff,
6946 tiff_image_p,
6947 tiff_load,
6948 x_clear_image,
6949 NULL
6950};
6951
6952/* Return non-zero if OBJECT is a valid TIFF image specification. */
6953
6954static int
6955tiff_image_p (object)
6956 Lisp_Object object;
6957{
6958 struct image_keyword fmt[TIFF_LAST];
6959 bcopy (tiff_format, fmt, sizeof fmt);
6960
6961 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff))
6962 return 0;
6963
6964 /* Must specify either the :data or :file keyword. */
6965 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
6966}
6967
9e2a2647 6968#endif /* HAVE_TIFF || HAVE_NS */
4ef0d4d0
KS
6969
6970#ifdef HAVE_TIFF
6971
6972#include <tiffio.h>
6973
6974#ifdef HAVE_NTGUI
6975
6976/* TIFF library details. */
6977DEF_IMGLIB_FN (TIFFSetErrorHandler);
6978DEF_IMGLIB_FN (TIFFSetWarningHandler);
6979DEF_IMGLIB_FN (TIFFOpen);
6980DEF_IMGLIB_FN (TIFFClientOpen);
6981DEF_IMGLIB_FN (TIFFGetField);
6982DEF_IMGLIB_FN (TIFFReadRGBAImage);
6983DEF_IMGLIB_FN (TIFFClose);
58279503 6984DEF_IMGLIB_FN (TIFFSetDirectory);
4ef0d4d0
KS
6985
6986static int
0855eb52 6987init_tiff_functions (Lisp_Object libraries)
4ef0d4d0
KS
6988{
6989 HMODULE library;
6990
0855eb52 6991 if (!(library = w32_delayed_load (libraries, Qtiff)))
4ef0d4d0
KS
6992 return 0;
6993
6994 LOAD_IMGLIB_FN (library, TIFFSetErrorHandler);
6995 LOAD_IMGLIB_FN (library, TIFFSetWarningHandler);
6996 LOAD_IMGLIB_FN (library, TIFFOpen);
6997 LOAD_IMGLIB_FN (library, TIFFClientOpen);
6998 LOAD_IMGLIB_FN (library, TIFFGetField);
6999 LOAD_IMGLIB_FN (library, TIFFReadRGBAImage);
7000 LOAD_IMGLIB_FN (library, TIFFClose);
58279503 7001 LOAD_IMGLIB_FN (library, TIFFSetDirectory);
4ef0d4d0
KS
7002 return 1;
7003}
7004
7005#else
7006
7007#define fn_TIFFSetErrorHandler TIFFSetErrorHandler
7008#define fn_TIFFSetWarningHandler TIFFSetWarningHandler
7009#define fn_TIFFOpen TIFFOpen
7010#define fn_TIFFClientOpen TIFFClientOpen
7011#define fn_TIFFGetField TIFFGetField
7012#define fn_TIFFReadRGBAImage TIFFReadRGBAImage
7013#define fn_TIFFClose TIFFClose
58279503 7014#define fn_TIFFSetDirectory TIFFSetDirectory
4ef0d4d0
KS
7015#endif /* HAVE_NTGUI */
7016
7017
7018/* Reading from a memory buffer for TIFF images Based on the PNG
7019 memory source, but we have to provide a lot of extra functions.
7020 Blah.
7021
7022 We really only need to implement read and seek, but I am not
7023 convinced that the TIFF library is smart enough not to destroy
7024 itself if we only hand it the function pointers we need to
7025 override. */
7026
7027typedef struct
7028{
7029 unsigned char *bytes;
7030 size_t len;
7031 int index;
7032}
7033tiff_memory_source;
7034
7035static size_t
7036tiff_read_from_memory (data, buf, size)
7037 thandle_t data;
7038 tdata_t buf;
7039 tsize_t size;
7040{
7041 tiff_memory_source *src = (tiff_memory_source *) data;
7042
7043 if (size > src->len - src->index)
7044 return (size_t) -1;
7045 bcopy (src->bytes + src->index, buf, size);
7046 src->index += size;
7047 return size;
7048}
7049
7050static size_t
7051tiff_write_from_memory (data, buf, size)
7052 thandle_t data;
7053 tdata_t buf;
7054 tsize_t size;
7055{
7056 return (size_t) -1;
7057}
7058
7059static toff_t
7060tiff_seek_in_memory (data, off, whence)
7061 thandle_t data;
7062 toff_t off;
7063 int whence;
7064{
7065 tiff_memory_source *src = (tiff_memory_source *) data;
7066 int idx;
7067
7068 switch (whence)
7069 {
7070 case SEEK_SET: /* Go from beginning of source. */
7071 idx = off;
7072 break;
7073
7074 case SEEK_END: /* Go from end of source. */
7075 idx = src->len + off;
7076 break;
7077
7078 case SEEK_CUR: /* Go from current position. */
7079 idx = src->index + off;
7080 break;
7081
7082 default: /* Invalid `whence'. */
7083 return -1;
7084 }
7085
7086 if (idx > src->len || idx < 0)
7087 return -1;
7088
7089 src->index = idx;
7090 return src->index;
7091}
7092
7093static int
7094tiff_close_memory (data)
7095 thandle_t data;
7096{
7097 /* NOOP */
7098 return 0;
7099}
7100
7101static int
7102tiff_mmap_memory (data, pbase, psize)
7103 thandle_t data;
7104 tdata_t *pbase;
7105 toff_t *psize;
7106{
7107 /* It is already _IN_ memory. */
7108 return 0;
7109}
7110
7111static void
7112tiff_unmap_memory (data, base, size)
7113 thandle_t data;
7114 tdata_t base;
7115 toff_t size;
7116{
7117 /* We don't need to do this. */
7118}
7119
7120static toff_t
7121tiff_size_of_memory (data)
7122 thandle_t data;
7123{
7124 return ((tiff_memory_source *) data)->len;
7125}
7126
7127
7128static void
7129tiff_error_handler (title, format, ap)
7130 const char *title, *format;
7131 va_list ap;
7132{
7133 char buf[512];
7134 int len;
7135
7136 len = sprintf (buf, "TIFF error: %s ", title);
7137 vsprintf (buf + len, format, ap);
7138 add_to_log (buf, Qnil, Qnil);
7139}
7140
7141
7142static void
7143tiff_warning_handler (title, format, ap)
7144 const char *title, *format;
7145 va_list ap;
7146{
7147 char buf[512];
7148 int len;
7149
7150 len = sprintf (buf, "TIFF warning: %s ", title);
7151 vsprintf (buf + len, format, ap);
7152 add_to_log (buf, Qnil, Qnil);
7153}
7154
7155
7156/* Load TIFF image IMG for use on frame F. Value is non-zero if
7157 successful. */
7158
7159static int
7160tiff_load (f, img)
7161 struct frame *f;
7162 struct image *img;
7163{
7164 Lisp_Object file, specified_file;
7165 Lisp_Object specified_data;
7166 TIFF *tiff;
58279503 7167 int width, height, x, y, count;
4ef0d4d0 7168 uint32 *buf;
58279503 7169 int rc, rc2;
4ef0d4d0
KS
7170 XImagePtr ximg;
7171 struct gcpro gcpro1;
7172 tiff_memory_source memsrc;
58279503 7173 Lisp_Object image;
4ef0d4d0
KS
7174
7175 specified_file = image_spec_value (img->spec, QCfile, NULL);
7176 specified_data = image_spec_value (img->spec, QCdata, NULL);
7177 file = Qnil;
7178 GCPRO1 (file);
7179
7180 fn_TIFFSetErrorHandler (tiff_error_handler);
7181 fn_TIFFSetWarningHandler (tiff_warning_handler);
7182
7183 if (NILP (specified_data))
7184 {
7185 /* Read from a file */
7186 file = x_find_image_file (specified_file);
7187 if (!STRINGP (file))
7188 {
7189 image_error ("Cannot find image file `%s'", specified_file, Qnil);
7190 UNGCPRO;
7191 return 0;
7192 }
7193
2e09fef1
EZ
7194 /* Try to open the image file. Casting return value avoids a
7195 GCC warning on W32. */
7196 tiff = (TIFF *)fn_TIFFOpen (SDATA (file), "r");
4ef0d4d0
KS
7197 if (tiff == NULL)
7198 {
7199 image_error ("Cannot open `%s'", file, Qnil);
7200 UNGCPRO;
7201 return 0;
7202 }
7203 }
7204 else
7205 {
7206 /* Memory source! */
7207 memsrc.bytes = SDATA (specified_data);
7208 memsrc.len = SBYTES (specified_data);
7209 memsrc.index = 0;
7210
2e09fef1
EZ
7211 /* Casting return value avoids a GCC warning on W32. */
7212 tiff = (TIFF *)fn_TIFFClientOpen ("memory_source", "r", &memsrc,
7213 (TIFFReadWriteProc) tiff_read_from_memory,
7214 (TIFFReadWriteProc) tiff_write_from_memory,
7215 tiff_seek_in_memory,
7216 tiff_close_memory,
7217 tiff_size_of_memory,
7218 tiff_mmap_memory,
7219 tiff_unmap_memory);
4ef0d4d0
KS
7220
7221 if (!tiff)
7222 {
7223 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
7224 UNGCPRO;
7225 return 0;
7226 }
7227 }
7228
58279503
JR
7229 image = image_spec_value (img->spec, QCindex, NULL);
7230 if (INTEGERP (image))
7231 {
7232 int ino = XFASTINT (image);
7233 if (!fn_TIFFSetDirectory (tiff, ino))
7234 {
7235 image_error ("Invalid image number `%s' in image `%s'",
7236 image, img->spec);
7237 fn_TIFFClose (tiff);
7238 UNGCPRO;
7239 return 0;
7240 }
7241 }
7242
4ef0d4d0
KS
7243 /* Get width and height of the image, and allocate a raster buffer
7244 of width x height 32-bit values. */
7245 fn_TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
7246 fn_TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
f1f25b99
CY
7247
7248 if (!check_image_size (f, width, height))
7249 {
10ea2b82 7250 image_error ("Invalid image size (see `max-image-size')", Qnil, Qnil);
58279503 7251 fn_TIFFClose (tiff);
f1f25b99
CY
7252 UNGCPRO;
7253 return 0;
7254 }
7255
4ef0d4d0
KS
7256 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
7257
7258 rc = fn_TIFFReadRGBAImage (tiff, width, height, buf, 0);
58279503
JR
7259
7260 /* Count the number of images in the file. */
7261 for (count = 1, rc2 = 1; rc2; count++)
7262 rc2 = fn_TIFFSetDirectory (tiff, count);
7263
7264 if (count > 1)
7265 img->data.lisp_val = Fcons (Qcount,
7266 Fcons (make_number (count),
7267 img->data.lisp_val));
7268
4ef0d4d0
KS
7269 fn_TIFFClose (tiff);
7270 if (!rc)
7271 {
7272 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
7273 xfree (buf);
7274 UNGCPRO;
7275 return 0;
7276 }
7277
7278 /* Create the X image and pixmap. */
7279 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
7280 {
7281 xfree (buf);
7282 UNGCPRO;
7283 return 0;
7284 }
7285
7286 /* Initialize the color table. */
7287 init_color_table ();
7288
7289 /* Process the pixel raster. Origin is in the lower-left corner. */
7290 for (y = 0; y < height; ++y)
7291 {
7292 uint32 *row = buf + y * width;
7293
7294 for (x = 0; x < width; ++x)
7295 {
7296 uint32 abgr = row[x];
7297 int r = TIFFGetR (abgr) << 8;
7298 int g = TIFFGetG (abgr) << 8;
7299 int b = TIFFGetB (abgr) << 8;
7300 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
7301 }
7302 }
7303
7304#ifdef COLOR_TABLE_SUPPORT
7305 /* Remember the colors allocated for the image. Free the color table. */
7306 img->colors = colors_in_color_table (&img->ncolors);
7307 free_color_table ();
7308#endif /* COLOR_TABLE_SUPPORT */
7309
7310 img->width = width;
7311 img->height = height;
7312
7313 /* Maybe fill in the background field while we have ximg handy. */
7314 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
2e09fef1
EZ
7315 /* Casting avoids a GCC warning on W32. */
7316 IMAGE_BACKGROUND (img, f, (XImagePtr_or_DC)ximg);
4ef0d4d0
KS
7317
7318 /* Put the image into the pixmap, then free the X image and its buffer. */
7319 x_put_x_image (f, ximg, img->pixmap, width, height);
7320 x_destroy_x_image (ximg);
7321 xfree (buf);
7322
7323 UNGCPRO;
7324 return 1;
7325}
7326
7327#else /* HAVE_TIFF */
7328
edfda783
AR
7329#ifdef HAVE_NS
7330static int
7331tiff_load (struct frame *f, struct image *img)
7332{
7333 return ns_load_image(f, img,
7334 image_spec_value (img->spec, QCfile, NULL),
7335 image_spec_value (img->spec, QCdata, NULL));
7336}
7337#endif /* HAVE_NS */
7338
4ef0d4d0
KS
7339#endif /* !HAVE_TIFF */
7340
7341
7342\f
7343/***********************************************************************
7344 GIF
7345 ***********************************************************************/
7346
9e2a2647 7347#if defined (HAVE_GIF) || defined (HAVE_NS)
4ef0d4d0
KS
7348
7349static int gif_image_p P_ ((Lisp_Object object));
7350static int gif_load P_ ((struct frame *f, struct image *img));
6ac3c7bb 7351static void gif_clear_image P_ ((struct frame *f, struct image *img));
4ef0d4d0
KS
7352
7353/* The symbol `gif' identifying images of this type. */
7354
7355Lisp_Object Qgif;
7356
7357/* Indices of image specification fields in gif_format, below. */
7358
7359enum gif_keyword_index
7360{
7361 GIF_TYPE,
7362 GIF_DATA,
7363 GIF_FILE,
7364 GIF_ASCENT,
7365 GIF_MARGIN,
7366 GIF_RELIEF,
7367 GIF_ALGORITHM,
7368 GIF_HEURISTIC_MASK,
7369 GIF_MASK,
7370 GIF_IMAGE,
7371 GIF_BACKGROUND,
7372 GIF_LAST
7373};
7374
7375/* Vector of image_keyword structures describing the format
7376 of valid user-defined image specifications. */
7377
7378static struct image_keyword gif_format[GIF_LAST] =
7379{
7380 {":type", IMAGE_SYMBOL_VALUE, 1},
7381 {":data", IMAGE_STRING_VALUE, 0},
7382 {":file", IMAGE_STRING_VALUE, 0},
7383 {":ascent", IMAGE_ASCENT_VALUE, 0},
7384 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
7385 {":relief", IMAGE_INTEGER_VALUE, 0},
7386 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7387 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7388 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
58279503 7389 {":index", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
4ef0d4d0
KS
7390 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
7391};
7392
7393/* Structure describing the image type `gif'. */
7394
7395static struct image_type gif_type =
7396{
7397 &Qgif,
7398 gif_image_p,
7399 gif_load,
6ac3c7bb 7400 gif_clear_image,
4ef0d4d0
KS
7401 NULL
7402};
7403
6ac3c7bb
KS
7404/* Free X resources of GIF image IMG which is used on frame F. */
7405
7406static void
7407gif_clear_image (f, img)
7408 struct frame *f;
7409 struct image *img;
7410{
7411 /* IMG->data.ptr_val may contain extension data. */
7412 img->data.lisp_val = Qnil;
7413 x_clear_image (f, img);
7414}
7415
4ef0d4d0
KS
7416/* Return non-zero if OBJECT is a valid GIF image specification. */
7417
7418static int
7419gif_image_p (object)
7420 Lisp_Object object;
7421{
7422 struct image_keyword fmt[GIF_LAST];
7423 bcopy (gif_format, fmt, sizeof fmt);
7424
7425 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif))
7426 return 0;
7427
7428 /* Must specify either the :data or :file keyword. */
7429 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
7430}
7431
9e2a2647 7432#endif /* HAVE_GIF */
4ef0d4d0
KS
7433
7434#ifdef HAVE_GIF
7435
9e2a2647 7436#if defined (HAVE_NTGUI)
2e09fef1
EZ
7437/* winuser.h might define DrawText to DrawTextA or DrawTextW.
7438 Undefine before redefining to avoid a preprocessor warning. */
7439#ifdef DrawText
7440#undef DrawText
7441#endif
4ef0d4d0
KS
7442/* avoid conflict with QuickdrawText.h */
7443#define DrawText gif_DrawText
7444#include <gif_lib.h>
7445#undef DrawText
7446
9e2a2647 7447#else /* HAVE_NTGUI */
4ef0d4d0
KS
7448
7449#include <gif_lib.h>
7450
9e2a2647 7451#endif /* HAVE_NTGUI */
4ef0d4d0
KS
7452
7453
7454#ifdef HAVE_NTGUI
7455
7456/* GIF library details. */
7457DEF_IMGLIB_FN (DGifCloseFile);
7458DEF_IMGLIB_FN (DGifSlurp);
7459DEF_IMGLIB_FN (DGifOpen);
7460DEF_IMGLIB_FN (DGifOpenFileName);
7461
7462static int
0855eb52 7463init_gif_functions (Lisp_Object libraries)
4ef0d4d0
KS
7464{
7465 HMODULE library;
7466
0855eb52 7467 if (!(library = w32_delayed_load (libraries, Qgif)))
4ef0d4d0
KS
7468 return 0;
7469
7470 LOAD_IMGLIB_FN (library, DGifCloseFile);
7471 LOAD_IMGLIB_FN (library, DGifSlurp);
7472 LOAD_IMGLIB_FN (library, DGifOpen);
7473 LOAD_IMGLIB_FN (library, DGifOpenFileName);
7474 return 1;
7475}
7476
7477#else
7478
7479#define fn_DGifCloseFile DGifCloseFile
7480#define fn_DGifSlurp DGifSlurp
7481#define fn_DGifOpen DGifOpen
7482#define fn_DGifOpenFileName DGifOpenFileName
7483
7484#endif /* HAVE_NTGUI */
7485
7486/* Reading a GIF image from memory
7487 Based on the PNG memory stuff to a certain extent. */
7488
7489typedef struct
7490{
7491 unsigned char *bytes;
7492 size_t len;
7493 int index;
7494}
7495gif_memory_source;
7496
7497/* Make the current memory source available to gif_read_from_memory.
7498 It's done this way because not all versions of libungif support
7499 a UserData field in the GifFileType structure. */
7500static gif_memory_source *current_gif_memory_src;
7501
7502static int
7503gif_read_from_memory (file, buf, len)
7504 GifFileType *file;
7505 GifByteType *buf;
7506 int len;
7507{
7508 gif_memory_source *src = current_gif_memory_src;
7509
7510 if (len > src->len - src->index)
7511 return -1;
7512
7513 bcopy (src->bytes + src->index, buf, len);
7514 src->index += len;
7515 return len;
7516}
7517
7518
7519/* Load GIF image IMG for use on frame F. Value is non-zero if
7520 successful. */
7521
aca946f3
GM
7522static int interlace_start[] = {0, 4, 2, 1};
7523static int interlace_increment[] = {8, 8, 4, 2};
7524
4ef0d4d0
KS
7525static int
7526gif_load (f, img)
7527 struct frame *f;
7528 struct image *img;
7529{
7530 Lisp_Object file, specified_file;
7531 Lisp_Object specified_data;
7532 int rc, width, height, x, y, i;
7533 XImagePtr ximg;
7534 ColorMapObject *gif_color_map;
7535 unsigned long pixel_colors[256];
7536 GifFileType *gif;
7537 struct gcpro gcpro1;
7538 Lisp_Object image;
6ac3c7bb 7539 int ino, image_height, image_width;
4ef0d4d0
KS
7540 gif_memory_source memsrc;
7541 unsigned char *raster;
7542
7543 specified_file = image_spec_value (img->spec, QCfile, NULL);
7544 specified_data = image_spec_value (img->spec, QCdata, NULL);
7545 file = Qnil;
7546 GCPRO1 (file);
7547
7548 if (NILP (specified_data))
7549 {
7550 file = x_find_image_file (specified_file);
7551 if (!STRINGP (file))
7552 {
7553 image_error ("Cannot find image file `%s'", specified_file, Qnil);
7554 UNGCPRO;
7555 return 0;
7556 }
7557
2e09fef1
EZ
7558 /* Open the GIF file. Casting return value avoids a GCC warning
7559 on W32. */
7560 gif = (GifFileType *)fn_DGifOpenFileName (SDATA (file));
4ef0d4d0
KS
7561 if (gif == NULL)
7562 {
7563 image_error ("Cannot open `%s'", file, Qnil);
7564 UNGCPRO;
7565 return 0;
7566 }
7567 }
7568 else
7569 {
7570 /* Read from memory! */
7571 current_gif_memory_src = &memsrc;
7572 memsrc.bytes = SDATA (specified_data);
7573 memsrc.len = SBYTES (specified_data);
7574 memsrc.index = 0;
7575
2e09fef1 7576 /* Casting return value avoids a GCC warning on W32. */
5fc9fdeb 7577 gif = (GifFileType *) fn_DGifOpen (&memsrc, gif_read_from_memory);
4ef0d4d0
KS
7578 if (!gif)
7579 {
7580 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
7581 UNGCPRO;
7582 return 0;
7583 }
7584 }
7585
f1f25b99
CY
7586 /* Before reading entire contents, check the declared image size. */
7587 if (!check_image_size (f, gif->SWidth, gif->SHeight))
7588 {
10ea2b82 7589 image_error ("Invalid image size (see `max-image-size')", Qnil, Qnil);
f1f25b99
CY
7590 fn_DGifCloseFile (gif);
7591 UNGCPRO;
7592 return 0;
7593 }
7594
4ef0d4d0
KS
7595 /* Read entire contents. */
7596 rc = fn_DGifSlurp (gif);
7597 if (rc == GIF_ERROR)
7598 {
7599 image_error ("Error reading `%s'", img->spec, Qnil);
7600 fn_DGifCloseFile (gif);
7601 UNGCPRO;
7602 return 0;
7603 }
7604
7605 image = image_spec_value (img->spec, QCindex, NULL);
7606 ino = INTEGERP (image) ? XFASTINT (image) : 0;
7607 if (ino >= gif->ImageCount)
7608 {
7609 image_error ("Invalid image number `%s' in image `%s'",
7610 image, img->spec);
7611 fn_DGifCloseFile (gif);
7612 UNGCPRO;
7613 return 0;
7614 }
7615
6ac3c7bb
KS
7616 img->corners[TOP_CORNER] = gif->SavedImages[ino].ImageDesc.Top;
7617 img->corners[LEFT_CORNER] = gif->SavedImages[ino].ImageDesc.Left;
0f4aca46 7618 image_height = gif->SavedImages[ino].ImageDesc.Height;
6ac3c7bb
KS
7619 img->corners[BOT_CORNER] = img->corners[TOP_CORNER] + image_height;
7620 image_width = gif->SavedImages[ino].ImageDesc.Width;
7621 img->corners[RIGHT_CORNER] = img->corners[LEFT_CORNER] + image_width;
0f4aca46
KS
7622
7623 width = img->width = max (gif->SWidth,
7624 max (gif->Image.Left + gif->Image.Width,
6ac3c7bb 7625 img->corners[RIGHT_CORNER]));
0f4aca46
KS
7626 height = img->height = max (gif->SHeight,
7627 max (gif->Image.Top + gif->Image.Height,
6ac3c7bb 7628 img->corners[BOT_CORNER]));
4ef0d4d0 7629
f1f25b99
CY
7630 if (!check_image_size (f, width, height))
7631 {
10ea2b82 7632 image_error ("Invalid image size (see `max-image-size')", Qnil, Qnil);
f1f25b99
CY
7633 fn_DGifCloseFile (gif);
7634 UNGCPRO;
7635 return 0;
7636 }
7637
4ef0d4d0
KS
7638 /* Create the X image and pixmap. */
7639 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
7640 {
7641 fn_DGifCloseFile (gif);
7642 UNGCPRO;
7643 return 0;
7644 }
7645
7646 /* Allocate colors. */
7647 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
7648 if (!gif_color_map)
7649 gif_color_map = gif->SColorMap;
7650 init_color_table ();
7651 bzero (pixel_colors, sizeof pixel_colors);
7652
1ab2cd43
TTN
7653 if (gif_color_map)
7654 for (i = 0; i < gif_color_map->ColorCount; ++i)
7655 {
7656 int r = gif_color_map->Colors[i].Red << 8;
7657 int g = gif_color_map->Colors[i].Green << 8;
7658 int b = gif_color_map->Colors[i].Blue << 8;
7659 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
7660 }
4ef0d4d0
KS
7661
7662#ifdef COLOR_TABLE_SUPPORT
7663 img->colors = colors_in_color_table (&img->ncolors);
7664 free_color_table ();
7665#endif /* COLOR_TABLE_SUPPORT */
7666
7667 /* Clear the part of the screen image that are not covered by
7668 the image from the GIF file. Full animated GIF support
7669 requires more than can be done here (see the gif89 spec,
7670 disposal methods). Let's simply assume that the part
7671 not covered by a sub-image is in the frame's background color. */
6ac3c7bb 7672 for (y = 0; y < img->corners[TOP_CORNER]; ++y)
4ef0d4d0
KS
7673 for (x = 0; x < width; ++x)
7674 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
7675
6ac3c7bb 7676 for (y = img->corners[BOT_CORNER]; y < height; ++y)
4ef0d4d0
KS
7677 for (x = 0; x < width; ++x)
7678 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
7679
6ac3c7bb 7680 for (y = img->corners[TOP_CORNER]; y < img->corners[BOT_CORNER]; ++y)
4ef0d4d0 7681 {
6ac3c7bb 7682 for (x = 0; x < img->corners[LEFT_CORNER]; ++x)
4ef0d4d0 7683 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
6ac3c7bb 7684 for (x = img->corners[RIGHT_CORNER]; x < width; ++x)
4ef0d4d0
KS
7685 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
7686 }
7687
7688 /* Read the GIF image into the X image. We use a local variable
7689 `raster' here because RasterBits below is a char *, and invites
7690 problems with bytes >= 0x80. */
7691 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
7692
7693 if (gif->SavedImages[ino].ImageDesc.Interlace)
7694 {
4ef0d4d0
KS
7695 int pass;
7696 int row = interlace_start[0];
7697
7698 pass = 0;
7699
7700 for (y = 0; y < image_height; y++)
7701 {
7702 if (row >= image_height)
7703 {
7704 row = interlace_start[++pass];
7705 while (row >= image_height)
7706 row = interlace_start[++pass];
7707 }
7708
7709 for (x = 0; x < image_width; x++)
7710 {
7711 int i = raster[(y * image_width) + x];
6ac3c7bb
KS
7712 XPutPixel (ximg, x + img->corners[LEFT_CORNER],
7713 row + img->corners[TOP_CORNER], pixel_colors[i]);
4ef0d4d0
KS
7714 }
7715
7716 row += interlace_increment[pass];
7717 }
7718 }
7719 else
7720 {
7721 for (y = 0; y < image_height; ++y)
7722 for (x = 0; x < image_width; ++x)
7723 {
7724 int i = raster[y * image_width + x];
6ac3c7bb
KS
7725 XPutPixel (ximg, x + img->corners[LEFT_CORNER],
7726 y + img->corners[TOP_CORNER], pixel_colors[i]);
4ef0d4d0
KS
7727 }
7728 }
7729
6ac3c7bb
KS
7730 /* Save GIF image extension data for `image-extension-data'.
7731 Format is (count IMAGES FUNCTION "BYTES" ...). */
7732 img->data.lisp_val = Qnil;
7733 if (gif->SavedImages[ino].ExtensionBlockCount > 0)
7734 {
7735 ExtensionBlock *ext = gif->SavedImages[ino].ExtensionBlocks;
7736 for (i = 0; i < gif->SavedImages[ino].ExtensionBlockCount; i++, ext++)
7737 /* Append (... FUNCTION "BYTES") */
7738 img->data.lisp_val = Fcons (make_unibyte_string (ext->Bytes, ext->ByteCount),
7739 Fcons (make_number (ext->Function),
7740 img->data.lisp_val));
7741 img->data.lisp_val = Fnreverse (img->data.lisp_val);
7742 }
7743 if (gif->ImageCount > 1)
7744 img->data.lisp_val = Fcons (Qcount,
7745 Fcons (make_number (gif->ImageCount),
7746 img->data.lisp_val));
7747
4ef0d4d0
KS
7748 fn_DGifCloseFile (gif);
7749
7750 /* Maybe fill in the background field while we have ximg handy. */
7751 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
2e09fef1
EZ
7752 /* Casting avoids a GCC warning. */
7753 IMAGE_BACKGROUND (img, f, (XImagePtr_or_DC)ximg);
4ef0d4d0
KS
7754
7755 /* Put the image into the pixmap, then free the X image and its buffer. */
7756 x_put_x_image (f, ximg, img->pixmap, width, height);
7757 x_destroy_x_image (ximg);
7758
7759 UNGCPRO;
7760 return 1;
7761}
7762
2e09fef1 7763#else /* !HAVE_GIF */
4ef0d4d0 7764
edfda783
AR
7765#ifdef HAVE_NS
7766static int
7767gif_load (struct frame *f, struct image *img)
7768{
7769 return ns_load_image(f, img,
7770 image_spec_value (img->spec, QCfile, NULL),
7771 image_spec_value (img->spec, QCdata, NULL));
7772}
7773#endif /* HAVE_NS */
7774
4ef0d4d0
KS
7775#endif /* HAVE_GIF */
7776
7777
7778\f
4ab27a43
GM
7779/***********************************************************************
7780 SVG
7781 ***********************************************************************/
7782
7783#if defined (HAVE_RSVG)
7784
7785/* Function prototypes. */
7786
7787static int svg_image_p P_ ((Lisp_Object object));
7788static int svg_load P_ ((struct frame *f, struct image *img));
7789
7790static int svg_load_image P_ ((struct frame *, struct image *,
7791 unsigned char *, unsigned int));
7792
7793/* The symbol `svg' identifying images of this type. */
7794
7795Lisp_Object Qsvg;
7796
7797/* Indices of image specification fields in svg_format, below. */
7798
7799enum svg_keyword_index
7800{
7801 SVG_TYPE,
7802 SVG_DATA,
7803 SVG_FILE,
7804 SVG_ASCENT,
7805 SVG_MARGIN,
7806 SVG_RELIEF,
7807 SVG_ALGORITHM,
7808 SVG_HEURISTIC_MASK,
7809 SVG_MASK,
7810 SVG_BACKGROUND,
7811 SVG_LAST
7812};
7813
7814/* Vector of image_keyword structures describing the format
7815 of valid user-defined image specifications. */
7816
7817static struct image_keyword svg_format[SVG_LAST] =
7818{
7819 {":type", IMAGE_SYMBOL_VALUE, 1},
7820 {":data", IMAGE_STRING_VALUE, 0},
7821 {":file", IMAGE_STRING_VALUE, 0},
7822 {":ascent", IMAGE_ASCENT_VALUE, 0},
7823 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
7824 {":relief", IMAGE_INTEGER_VALUE, 0},
7825 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7826 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7827 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7828 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
7829};
7830
7831/* Structure describing the image type `svg'. Its the same type of
7832 structure defined for all image formats, handled by emacs image
7833 functions. See struct image_type in dispextern.h. */
7834
7835static struct image_type svg_type =
7836{
7837 /* An identifier showing that this is an image structure for the SVG format. */
7838 &Qsvg,
7839 /* Handle to a function that can be used to identify a SVG file. */
7840 svg_image_p,
7841 /* Handle to function used to load a SVG file. */
7842 svg_load,
7843 /* Handle to function to free sresources for SVG. */
7844 x_clear_image,
7845 /* An internal field to link to the next image type in a list of
7846 image types, will be filled in when registering the format. */
c21e6151 7847 NULL
4ab27a43
GM
7848};
7849
7850
7851/* Return non-zero if OBJECT is a valid SVG image specification. Do
7852 this by calling parse_image_spec and supplying the keywords that
7853 identify the SVG format. */
7854
7855static int
7856svg_image_p (object)
7857 Lisp_Object object;
7858{
7859 struct image_keyword fmt[SVG_LAST];
7860 bcopy (svg_format, fmt, sizeof fmt);
7861
7862 if (!parse_image_spec (object, fmt, SVG_LAST, Qsvg))
7863 return 0;
7864
7865 /* Must specify either the :data or :file keyword. */
7866 return fmt[SVG_FILE].count + fmt[SVG_DATA].count == 1;
7867}
7868
7869#include <librsvg/rsvg.h>
7870
5fc9fdeb
JR
7871#ifdef HAVE_NTGUI
7872
7873/* SVG library functions. */
7874DEF_IMGLIB_FN (rsvg_handle_new);
e025c9c2 7875DEF_IMGLIB_FN (rsvg_handle_get_dimensions);
5fc9fdeb
JR
7876DEF_IMGLIB_FN (rsvg_handle_write);
7877DEF_IMGLIB_FN (rsvg_handle_close);
7878DEF_IMGLIB_FN (rsvg_handle_get_pixbuf);
7879DEF_IMGLIB_FN (rsvg_handle_free);
7880
7881DEF_IMGLIB_FN (gdk_pixbuf_get_width);
7882DEF_IMGLIB_FN (gdk_pixbuf_get_height);
7883DEF_IMGLIB_FN (gdk_pixbuf_get_pixels);
7884DEF_IMGLIB_FN (gdk_pixbuf_get_rowstride);
7885DEF_IMGLIB_FN (gdk_pixbuf_get_colorspace);
7886DEF_IMGLIB_FN (gdk_pixbuf_get_n_channels);
7887DEF_IMGLIB_FN (gdk_pixbuf_get_has_alpha);
7888DEF_IMGLIB_FN (gdk_pixbuf_get_bits_per_sample);
7889
7890DEF_IMGLIB_FN (g_type_init);
7891DEF_IMGLIB_FN (g_object_unref);
7892DEF_IMGLIB_FN (g_error_free);
7893
df23bf08 7894Lisp_Object Qgdk_pixbuf, Qglib, Qgobject;
5fc9fdeb
JR
7895
7896static int
7897init_svg_functions (Lisp_Object libraries)
7898{
df23bf08 7899 HMODULE library, gdklib, glib, gobject;
5fc9fdeb
JR
7900
7901 if (!(glib = w32_delayed_load (libraries, Qglib))
df23bf08 7902 || !(gobject = w32_delayed_load (libraries, Qgobject))
5fc9fdeb
JR
7903 || !(gdklib = w32_delayed_load (libraries, Qgdk_pixbuf))
7904 || !(library = w32_delayed_load (libraries, Qsvg)))
7905 return 0;
7906
7907 LOAD_IMGLIB_FN (library, rsvg_handle_new);
e025c9c2 7908 LOAD_IMGLIB_FN (library, rsvg_handle_get_dimensions);
5fc9fdeb
JR
7909 LOAD_IMGLIB_FN (library, rsvg_handle_write);
7910 LOAD_IMGLIB_FN (library, rsvg_handle_close);
7911 LOAD_IMGLIB_FN (library, rsvg_handle_get_pixbuf);
7912 LOAD_IMGLIB_FN (library, rsvg_handle_free);
7913
7914 LOAD_IMGLIB_FN (gdklib, gdk_pixbuf_get_width);
7915 LOAD_IMGLIB_FN (gdklib, gdk_pixbuf_get_height);
7916 LOAD_IMGLIB_FN (gdklib, gdk_pixbuf_get_pixels);
7917 LOAD_IMGLIB_FN (gdklib, gdk_pixbuf_get_rowstride);
7918 LOAD_IMGLIB_FN (gdklib, gdk_pixbuf_get_colorspace);
7919 LOAD_IMGLIB_FN (gdklib, gdk_pixbuf_get_n_channels);
7920 LOAD_IMGLIB_FN (gdklib, gdk_pixbuf_get_has_alpha);
7921 LOAD_IMGLIB_FN (gdklib, gdk_pixbuf_get_bits_per_sample);
7922
df23bf08
JR
7923 LOAD_IMGLIB_FN (gobject, g_type_init);
7924 LOAD_IMGLIB_FN (gobject, g_object_unref);
5fc9fdeb 7925 LOAD_IMGLIB_FN (glib, g_error_free);
df23bf08 7926
5fc9fdeb
JR
7927 return 1;
7928}
4ab27a43 7929
5fc9fdeb
JR
7930#else
7931/* The following aliases for library functions allow dynamic loading
7932 to be used on some platforms. */
4ab27a43 7933#define fn_rsvg_handle_new rsvg_handle_new
e025c9c2 7934#define fn_rsvg_handle_get_dimensions rsvg_handle_get_dimensions
4ab27a43
GM
7935#define fn_rsvg_handle_write rsvg_handle_write
7936#define fn_rsvg_handle_close rsvg_handle_close
7937#define fn_rsvg_handle_get_pixbuf rsvg_handle_get_pixbuf
7938#define fn_rsvg_handle_free rsvg_handle_free
7939
5fc9fdeb
JR
7940#define fn_gdk_pixbuf_get_width gdk_pixbuf_get_width
7941#define fn_gdk_pixbuf_get_height gdk_pixbuf_get_height
7942#define fn_gdk_pixbuf_get_pixels gdk_pixbuf_get_pixels
7943#define fn_gdk_pixbuf_get_rowstride gdk_pixbuf_get_rowstride
7944#define fn_gdk_pixbuf_get_colorspace gdk_pixbuf_get_colorspace
7945#define fn_gdk_pixbuf_get_n_channels gdk_pixbuf_get_n_channels
7946#define fn_gdk_pixbuf_get_has_alpha gdk_pixbuf_get_has_alpha
4ab27a43
GM
7947#define fn_gdk_pixbuf_get_bits_per_sample gdk_pixbuf_get_bits_per_sample
7948
5fc9fdeb
JR
7949#define fn_g_type_init g_type_init
7950#define fn_g_object_unref g_object_unref
7951#define fn_g_error_free g_error_free
7952#endif /* !HAVE_NTGUI */
4ab27a43
GM
7953
7954/* Load SVG image IMG for use on frame F. Value is non-zero if
7955 successful. this function will go into the svg_type structure, and
7956 the prototype thus needs to be compatible with that structure. */
7957
7958static int
7959svg_load (f, img)
7960 struct frame *f;
7961 struct image *img;
7962{
7963 int success_p = 0;
7964 Lisp_Object file_name;
7965
7966 /* If IMG->spec specifies a file name, create a non-file spec from it. */
7967 file_name = image_spec_value (img->spec, QCfile, NULL);
7968 if (STRINGP (file_name))
7969 {
7970 Lisp_Object file;
7971 unsigned char *contents;
7972 int size;
7973 struct gcpro gcpro1;
7974
7975 file = x_find_image_file (file_name);
7976 GCPRO1 (file);
7977 if (!STRINGP (file))
c21e6151
YM
7978 {
7979 image_error ("Cannot find image file `%s'", file_name, Qnil);
7980 UNGCPRO;
7981 return 0;
7982 }
7983
4ab27a43
GM
7984 /* Read the entire file into memory. */
7985 contents = slurp_file (SDATA (file), &size);
7986 if (contents == NULL)
c21e6151
YM
7987 {
7988 image_error ("Error loading SVG image `%s'", img->spec, Qnil);
7989 UNGCPRO;
7990 return 0;
7991 }
4ab27a43 7992 /* If the file was slurped into memory properly, parse it. */
c21e6151 7993 success_p = svg_load_image (f, img, contents, size);
4ab27a43
GM
7994 xfree (contents);
7995 UNGCPRO;
7996 }
7997 /* Else its not a file, its a lisp object. Load the image from a
7998 lisp object rather than a file. */
7999 else
8000 {
8001 Lisp_Object data;
8002
8003 data = image_spec_value (img->spec, QCdata, NULL);
8004 success_p = svg_load_image (f, img, SDATA (data), SBYTES (data));
8005 }
8006
8007 return success_p;
8008}
8009
bbe6f2aa
JB
8010/* svg_load_image is a helper function for svg_load, which does the
8011 actual loading given contents and size, apart from frame and image
8012 structures, passed from svg_load.
4ab27a43 8013
bbe6f2aa 8014 Uses librsvg to do most of the image processing.
c21e6151 8015
bbe6f2aa 8016 Returns non-zero when successful. */
4ab27a43
GM
8017static int
8018svg_load_image (f, img, contents, size)
bbe6f2aa 8019 /* Pointer to emacs frame structure. */
4ab27a43
GM
8020 struct frame *f;
8021 /* Pointer to emacs image structure. */
8022 struct image *img;
8023 /* String containing the SVG XML data to be parsed. */
8024 unsigned char *contents;
8025 /* Size of data in bytes. */
8026 unsigned int size;
8027{
8028 RsvgHandle *rsvg_handle;
e025c9c2 8029 RsvgDimensionData dimension_data;
4ab27a43
GM
8030 GError *error = NULL;
8031 GdkPixbuf *pixbuf;
8032 int width;
8033 int height;
8034 const guint8 *pixels;
8035 int rowstride;
8036 XImagePtr ximg;
c21e6151 8037 Lisp_Object specified_bg;
4ab27a43
GM
8038 XColor background;
8039 int x;
8040 int y;
8041
8042 /* g_type_init is a glib function that must be called prior to using
8043 gnome type library functions. */
5fc9fdeb 8044 fn_g_type_init ();
4ab27a43 8045 /* Make a handle to a new rsvg object. */
8b7d0a16 8046 rsvg_handle = (RsvgHandle *) fn_rsvg_handle_new ();
4ab27a43
GM
8047
8048 /* Parse the contents argument and fill in the rsvg_handle. */
8049 fn_rsvg_handle_write (rsvg_handle, contents, size, &error);
e025c9c2 8050 if (error) goto rsvg_error;
4ab27a43
GM
8051
8052 /* The parsing is complete, rsvg_handle is ready to used, close it
8053 for further writes. */
8054 fn_rsvg_handle_close (rsvg_handle, &error);
e025c9c2
CY
8055 if (error) goto rsvg_error;
8056
8057 fn_rsvg_handle_get_dimensions (rsvg_handle, &dimension_data);
8058 if (! check_image_size (f, dimension_data.width, dimension_data.height))
10ea2b82
JR
8059 {
8060 image_error ("Invalid image size (see `max-image-size')", Qnil, Qnil);
8061 goto rsvg_error;
8062 }
b2996e57 8063
4ab27a43
GM
8064 /* We can now get a valid pixel buffer from the svg file, if all
8065 went ok. */
8b7d0a16 8066 pixbuf = (GdkPixbuf *) fn_rsvg_handle_get_pixbuf (rsvg_handle);
e025c9c2
CY
8067 if (!pixbuf) goto rsvg_error;
8068 fn_g_object_unref (rsvg_handle);
4ab27a43
GM
8069
8070 /* Extract some meta data from the svg handle. */
8071 width = fn_gdk_pixbuf_get_width (pixbuf);
8072 height = fn_gdk_pixbuf_get_height (pixbuf);
8b7d0a16 8073 pixels = (const guint8 *) fn_gdk_pixbuf_get_pixels (pixbuf);
4ab27a43
GM
8074 rowstride = fn_gdk_pixbuf_get_rowstride (pixbuf);
8075
8076 /* Validate the svg meta data. */
8077 eassert (fn_gdk_pixbuf_get_colorspace (pixbuf) == GDK_COLORSPACE_RGB);
8078 eassert (fn_gdk_pixbuf_get_n_channels (pixbuf) == 4);
8079 eassert (fn_gdk_pixbuf_get_has_alpha (pixbuf));
8080 eassert (fn_gdk_pixbuf_get_bits_per_sample (pixbuf) == 8);
8081
8082 /* Try to create a x pixmap to hold the svg pixmap. */
c21e6151
YM
8083 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
8084 {
5fc9fdeb 8085 fn_g_object_unref (pixbuf);
c21e6151
YM
8086 return 0;
8087 }
4ab27a43
GM
8088
8089 init_color_table ();
8090
c21e6151
YM
8091 /* Handle alpha channel by combining the image with a background
8092 color. */
8093 specified_bg = image_spec_value (img->spec, QCbackground, NULL);
8d3c4e79
CY
8094 if (!STRINGP (specified_bg)
8095 || !x_defined_color (f, SDATA (specified_bg), &background, 0))
c21e6151 8096 {
d7e008d0 8097#ifndef HAVE_NS
c21e6151
YM
8098 background.pixel = FRAME_BACKGROUND_PIXEL (f);
8099 x_query_color (f, &background);
d7e008d0
AR
8100#else
8101 ns_query_color(FRAME_BACKGROUND_COLOR (f), &background, 1);
8102#endif
c21e6151 8103 }
4ab27a43 8104
8d3c4e79
CY
8105 /* SVG pixmaps specify transparency in the last byte, so right
8106 shift 8 bits to get rid of it, since emacs doesn't support
8107 transparency. */
8108 background.red >>= 8;
8109 background.green >>= 8;
8110 background.blue >>= 8;
8111
4ab27a43
GM
8112 /* This loop handles opacity values, since Emacs assumes
8113 non-transparent images. Each pixel must be "flattened" by
bbe6f2aa
JB
8114 calculating the resulting color, given the transparency of the
8115 pixel, and the image background color. */
4ab27a43
GM
8116 for (y = 0; y < height; ++y)
8117 {
8118 for (x = 0; x < width; ++x)
8119 {
8120 unsigned red;
8121 unsigned green;
8122 unsigned blue;
8123 unsigned opacity;
8124
8125 red = *pixels++;
8126 green = *pixels++;
8127 blue = *pixels++;
8128 opacity = *pixels++;
8129
8130 red = ((red * opacity)
8131 + (background.red * ((1 << 8) - opacity)));
8132 green = ((green * opacity)
8133 + (background.green * ((1 << 8) - opacity)));
8134 blue = ((blue * opacity)
8135 + (background.blue * ((1 << 8) - opacity)));
8136
8137 XPutPixel (ximg, x, y, lookup_rgb_color (f, red, green, blue));
8138 }
8139
8140 pixels += rowstride - 4 * width;
8141 }
8142
8143#ifdef COLOR_TABLE_SUPPORT
8144 /* Remember colors allocated for this image. */
8145 img->colors = colors_in_color_table (&img->ncolors);
8146 free_color_table ();
8147#endif /* COLOR_TABLE_SUPPORT */
8148
5fc9fdeb 8149 fn_g_object_unref (pixbuf);
4ab27a43 8150
c21e6151
YM
8151 img->width = width;
8152 img->height = height;
8153
8154 /* Maybe fill in the background field while we have ximg handy.
8155 Casting avoids a GCC warning. */
8156 IMAGE_BACKGROUND (img, f, (XImagePtr_or_DC)ximg);
8157
4ab27a43
GM
8158 /* Put the image into the pixmap, then free the X image and its
8159 buffer. */
8160 x_put_x_image (f, ximg, img->pixmap, width, height);
8161 x_destroy_x_image (ximg);
8162
4ab27a43
GM
8163 return 1;
8164
8165 rsvg_error:
e025c9c2 8166 fn_g_object_unref (rsvg_handle);
4ab27a43
GM
8167 /* FIXME: Use error->message so the user knows what is the actual
8168 problem with the image. */
8169 image_error ("Error parsing SVG image `%s'", img->spec, Qnil);
5fc9fdeb 8170 fn_g_error_free (error);
4ab27a43
GM
8171 return 0;
8172}
8173
8174#endif /* defined (HAVE_RSVG) */
8175
8176
8177
4ef0d4d0
KS
8178\f
8179/***********************************************************************
8180 Ghostscript
8181 ***********************************************************************/
8182
8183#ifdef HAVE_X_WINDOWS
8184#define HAVE_GHOSTSCRIPT 1
8185#endif /* HAVE_X_WINDOWS */
8186
8187/* The symbol `postscript' identifying images of this type. */
8188
8189Lisp_Object Qpostscript;
8190
8191#ifdef HAVE_GHOSTSCRIPT
8192
8193static int gs_image_p P_ ((Lisp_Object object));
8194static int gs_load P_ ((struct frame *f, struct image *img));
8195static void gs_clear_image P_ ((struct frame *f, struct image *img));
8196
8197/* Keyword symbols. */
8198
8199Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
8200
8201/* Indices of image specification fields in gs_format, below. */
8202
8203enum gs_keyword_index
8204{
8205 GS_TYPE,
8206 GS_PT_WIDTH,
8207 GS_PT_HEIGHT,
8208 GS_FILE,
8209 GS_LOADER,
8210 GS_BOUNDING_BOX,
8211 GS_ASCENT,
8212 GS_MARGIN,
8213 GS_RELIEF,
8214 GS_ALGORITHM,
8215 GS_HEURISTIC_MASK,
8216 GS_MASK,
8217 GS_BACKGROUND,
8218 GS_LAST
8219};
8220
8221/* Vector of image_keyword structures describing the format
8222 of valid user-defined image specifications. */
8223
8224static struct image_keyword gs_format[GS_LAST] =
8225{
8226 {":type", IMAGE_SYMBOL_VALUE, 1},
8227 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
8228 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
8229 {":file", IMAGE_STRING_VALUE, 1},
8230 {":loader", IMAGE_FUNCTION_VALUE, 0},
8231 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
8232 {":ascent", IMAGE_ASCENT_VALUE, 0},
8233 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
8234 {":relief", IMAGE_INTEGER_VALUE, 0},
8235 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8236 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8237 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8238 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
8239};
8240
8241/* Structure describing the image type `ghostscript'. */
8242
8243static struct image_type gs_type =
8244{
8245 &Qpostscript,
8246 gs_image_p,
8247 gs_load,
8248 gs_clear_image,
8249 NULL
8250};
8251
8252
8253/* Free X resources of Ghostscript image IMG which is used on frame F. */
8254
8255static void
8256gs_clear_image (f, img)
8257 struct frame *f;
8258 struct image *img;
8259{
8260 /* IMG->data.ptr_val may contain a recorded colormap. */
8261 xfree (img->data.ptr_val);
8262 x_clear_image (f, img);
8263}
8264
8265
8266/* Return non-zero if OBJECT is a valid Ghostscript image
8267 specification. */
8268
8269static int
8270gs_image_p (object)
8271 Lisp_Object object;
8272{
8273 struct image_keyword fmt[GS_LAST];
8274 Lisp_Object tem;
8275 int i;
8276
8277 bcopy (gs_format, fmt, sizeof fmt);
8278
8279 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript))
8280 return 0;
8281
8282 /* Bounding box must be a list or vector containing 4 integers. */
8283 tem = fmt[GS_BOUNDING_BOX].value;
8284 if (CONSP (tem))
8285 {
8286 for (i = 0; i < 4; ++i, tem = XCDR (tem))
8287 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
8288 return 0;
8289 if (!NILP (tem))
8290 return 0;
8291 }
8292 else if (VECTORP (tem))
8293 {
8294 if (XVECTOR (tem)->size != 4)
8295 return 0;
8296 for (i = 0; i < 4; ++i)
8297 if (!INTEGERP (XVECTOR (tem)->contents[i]))
8298 return 0;
8299 }
8300 else
8301 return 0;
8302
8303 return 1;
8304}
8305
8306
8307/* Load Ghostscript image IMG for use on frame F. Value is non-zero
8308 if successful. */
8309
8310static int
8311gs_load (f, img)
8312 struct frame *f;
8313 struct image *img;
8314{
8315 char buffer[100];
8316 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
8317 struct gcpro gcpro1, gcpro2;
8318 Lisp_Object frame;
8319 double in_width, in_height;
8320 Lisp_Object pixel_colors = Qnil;
8321
8322 /* Compute pixel size of pixmap needed from the given size in the
8323 image specification. Sizes in the specification are in pt. 1 pt
8324 = 1/72 in, xdpi and ydpi are stored in the frame's X display
8325 info. */
8326 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
8327 in_width = XFASTINT (pt_width) / 72.0;
8328 img->width = in_width * FRAME_X_DISPLAY_INFO (f)->resx;
8329 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
8330 in_height = XFASTINT (pt_height) / 72.0;
8331 img->height = in_height * FRAME_X_DISPLAY_INFO (f)->resy;
8332
f1f25b99
CY
8333 if (!check_image_size (f, img->width, img->height))
8334 {
10ea2b82 8335 image_error ("Invalid image size (see `max-image-size')", Qnil, Qnil);
f1f25b99
CY
8336 return 0;
8337 }
8338
4ef0d4d0
KS
8339 /* Create the pixmap. */
8340 xassert (img->pixmap == NO_PIXMAP);
8341
8342 /* Only W32 version did BLOCK_INPUT here. ++kfs */
8343 BLOCK_INPUT;
8344 img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8345 img->width, img->height,
8346 DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
8347 UNBLOCK_INPUT;
8348
8349 if (!img->pixmap)
8350 {
8351 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
8352 return 0;
8353 }
8354
8355 /* Call the loader to fill the pixmap. It returns a process object
8356 if successful. We do not record_unwind_protect here because
8357 other places in redisplay like calling window scroll functions
8358 don't either. Let the Lisp loader use `unwind-protect' instead. */
8359 GCPRO2 (window_and_pixmap_id, pixel_colors);
8360
8361 sprintf (buffer, "%lu %lu",
8362 (unsigned long) FRAME_X_WINDOW (f),
8363 (unsigned long) img->pixmap);
8364 window_and_pixmap_id = build_string (buffer);
8365
8366 sprintf (buffer, "%lu %lu",
8367 FRAME_FOREGROUND_PIXEL (f),
8368 FRAME_BACKGROUND_PIXEL (f));
8369 pixel_colors = build_string (buffer);
8370
8371 XSETFRAME (frame, f);
8372 loader = image_spec_value (img->spec, QCloader, NULL);
8373 if (NILP (loader))
8374 loader = intern ("gs-load-image");
8375
8376 img->data.lisp_val = call6 (loader, frame, img->spec,
8377 make_number (img->width),
8378 make_number (img->height),
8379 window_and_pixmap_id,
8380 pixel_colors);
8381 UNGCPRO;
8382 return PROCESSP (img->data.lisp_val);
8383}
8384
8385
8386/* Kill the Ghostscript process that was started to fill PIXMAP on
8387 frame F. Called from XTread_socket when receiving an event
8388 telling Emacs that Ghostscript has finished drawing. */
8389
8390void
8391x_kill_gs_process (pixmap, f)
8392 Pixmap pixmap;
8393 struct frame *f;
8394{
354884c4 8395 struct image_cache *c = FRAME_IMAGE_CACHE (f);
4ef0d4d0
KS
8396 int class, i;
8397 struct image *img;
8398
8399 /* Find the image containing PIXMAP. */
8400 for (i = 0; i < c->used; ++i)
8401 if (c->images[i]->pixmap == pixmap)
8402 break;
8403
8404 /* Should someone in between have cleared the image cache, for
8405 instance, give up. */
8406 if (i == c->used)
8407 return;
8408
8409 /* Kill the GS process. We should have found PIXMAP in the image
8410 cache and its image should contain a process object. */
8411 img = c->images[i];
8412 xassert (PROCESSP (img->data.lisp_val));
8413 Fkill_process (img->data.lisp_val, Qnil);
8414 img->data.lisp_val = Qnil;
8415
8416#if defined (HAVE_X_WINDOWS)
8417
8418 /* On displays with a mutable colormap, figure out the colors
8419 allocated for the image by looking at the pixels of an XImage for
8420 img->pixmap. */
8421 class = FRAME_X_VISUAL (f)->class;
8422 if (class != StaticColor && class != StaticGray && class != TrueColor)
8423 {
8424 XImagePtr ximg;
8425
8426 BLOCK_INPUT;
8427
8428 /* Try to get an XImage for img->pixmep. */
8429 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
8430 0, 0, img->width, img->height, ~0, ZPixmap);
8431 if (ximg)
8432 {
8433 int x, y;
8434
8435 /* Initialize the color table. */
8436 init_color_table ();
8437
8438 /* For each pixel of the image, look its color up in the
8439 color table. After having done so, the color table will
8440 contain an entry for each color used by the image. */
8441 for (y = 0; y < img->height; ++y)
8442 for (x = 0; x < img->width; ++x)
8443 {
8444 unsigned long pixel = XGetPixel (ximg, x, y);
8445 lookup_pixel_color (f, pixel);
8446 }
8447
8448 /* Record colors in the image. Free color table and XImage. */
8449#ifdef COLOR_TABLE_SUPPORT
8450 img->colors = colors_in_color_table (&img->ncolors);
8451 free_color_table ();
8452#endif
8453 XDestroyImage (ximg);
8454
8455#if 0 /* This doesn't seem to be the case. If we free the colors
8456 here, we get a BadAccess later in x_clear_image when
8457 freeing the colors. */
8458 /* We have allocated colors once, but Ghostscript has also
8459 allocated colors on behalf of us. So, to get the
8460 reference counts right, free them once. */
8461 if (img->ncolors)
8462 x_free_colors (f, img->colors, img->ncolors);
8463#endif
8464 }
8465 else
8466 image_error ("Cannot get X image of `%s'; colors will not be freed",
8467 img->spec, Qnil);
8468
8469 UNBLOCK_INPUT;
8470 }
8471#endif /* HAVE_X_WINDOWS */
8472
8473 /* Now that we have the pixmap, compute mask and transform the
8474 image if requested. */
8475 BLOCK_INPUT;
8476 postprocess_image (f, img);
8477 UNBLOCK_INPUT;
8478}
8479
8480#endif /* HAVE_GHOSTSCRIPT */
8481
8482\f
8483/***********************************************************************
8484 Tests
8485 ***********************************************************************/
8486
8487#if GLYPH_DEBUG
8488
8489DEFUN ("imagep", Fimagep, Simagep, 1, 1, 0,
8490 doc: /* Value is non-nil if SPEC is a valid image specification. */)
8491 (spec)
8492 Lisp_Object spec;
8493{
8494 return valid_image_p (spec) ? Qt : Qnil;
8495}
8496
8497
8498DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0, "")
8499 (spec)
8500 Lisp_Object spec;
8501{
8502 int id = -1;
8503
8504 if (valid_image_p (spec))
8505 id = lookup_image (SELECTED_FRAME (), spec);
8506
8507 debug_print (spec);
8508 return make_number (id);
8509}
8510
8511#endif /* GLYPH_DEBUG != 0 */
8512
8513
8514/***********************************************************************
8515 Initialization
8516 ***********************************************************************/
8517
0855eb52
JB
8518#ifdef HAVE_NTGUI
8519/* Image types that rely on external libraries are loaded dynamically
8520 if the library is available. */
adac86db 8521#define CHECK_LIB_AVAILABLE(image_type, init_lib_fn, libraries) \
0855eb52
JB
8522 define_image_type (image_type, init_lib_fn (libraries))
8523#else
adac86db 8524#define CHECK_LIB_AVAILABLE(image_type, init_lib_fn, libraries) \
e0e30823 8525 define_image_type (image_type, 1)
0855eb52
JB
8526#endif /* HAVE_NTGUI */
8527
8528DEFUN ("init-image-library", Finit_image_library, Sinit_image_library, 2, 2, 0,
8529 doc: /* Initialize image library implementing image type TYPE.
8530Return non-nil if TYPE is a supported image type.
8531
8532Image types pbm and xbm are prebuilt; other types are loaded here.
8533Libraries to load are specified in alist LIBRARIES (usually, the value
adac86db 8534of `image-library-alist', which see). */)
0855eb52 8535 (type, libraries)
adac86db 8536 Lisp_Object type, libraries;
0855eb52
JB
8537{
8538 Lisp_Object tested;
8539
8540 /* Don't try to reload the library. */
8541 tested = Fassq (type, Vimage_type_cache);
8542 if (CONSP (tested))
8543 return XCDR (tested);
8544
9e2a2647 8545#if defined (HAVE_XPM) || defined (HAVE_NS)
0855eb52 8546 if (EQ (type, Qxpm))
adac86db 8547 return CHECK_LIB_AVAILABLE (&xpm_type, init_xpm_functions, libraries);
0855eb52
JB
8548#endif
8549
9e2a2647 8550#if defined (HAVE_JPEG) || defined (HAVE_NS)
0855eb52 8551 if (EQ (type, Qjpeg))
adac86db 8552 return CHECK_LIB_AVAILABLE (&jpeg_type, init_jpeg_functions, libraries);
0855eb52
JB
8553#endif
8554
9e2a2647 8555#if defined (HAVE_TIFF) || defined (HAVE_NS)
0855eb52 8556 if (EQ (type, Qtiff))
adac86db 8557 return CHECK_LIB_AVAILABLE (&tiff_type, init_tiff_functions, libraries);
0855eb52
JB
8558#endif
8559
9e2a2647 8560#if defined (HAVE_GIF) || defined (HAVE_NS)
0855eb52 8561 if (EQ (type, Qgif))
adac86db 8562 return CHECK_LIB_AVAILABLE (&gif_type, init_gif_functions, libraries);
0855eb52
JB
8563#endif
8564
9e2a2647 8565#if defined (HAVE_PNG) || defined (HAVE_NS)
0855eb52 8566 if (EQ (type, Qpng))
adac86db 8567 return CHECK_LIB_AVAILABLE (&png_type, init_png_functions, libraries);
0855eb52
JB
8568#endif
8569
4ab27a43
GM
8570#if defined (HAVE_RSVG)
8571 if (EQ (type, Qsvg))
8572 return CHECK_LIB_AVAILABLE (&svg_type, init_svg_functions, libraries);
8573#endif
c21e6151 8574
0855eb52
JB
8575#ifdef HAVE_GHOSTSCRIPT
8576 if (EQ (type, Qpostscript))
adac86db 8577 return CHECK_LIB_AVAILABLE (&gs_type, init_gs_functions, libraries);
0855eb52
JB
8578#endif
8579
8580 /* If the type is not recognized, avoid testing it ever again. */
adac86db 8581 CACHE_IMAGE_TYPE (type, Qnil);
0855eb52
JB
8582 return Qnil;
8583}
8584
4ef0d4d0
KS
8585void
8586syms_of_image ()
8587{
2a611c1a
JB
8588 extern Lisp_Object Qrisky_local_variable; /* Syms_of_xdisp has already run. */
8589
6e6fc3fd
RS
8590 /* Initialize this only once, since that's what we do with Vimage_types
8591 and they are supposed to be in sync. Initializing here gives correct
8592 operation on GNU/Linux of calling dump-emacs after loading some images. */
8593 image_types = NULL;
8594
0855eb52
JB
8595 /* Must be defined now becase we're going to update it below, while
8596 defining the supported image types. */
8597 DEFVAR_LISP ("image-types", &Vimage_types,
8598 doc: /* List of potentially supported image types.
bbe6f2aa 8599Each element of the list is a symbol for an image type, like 'jpeg or 'png.
0855eb52
JB
8600To check whether it is really supported, use `image-type-available-p'. */);
8601 Vimage_types = Qnil;
8602
2a611c1a
JB
8603 DEFVAR_LISP ("image-library-alist", &Vimage_library_alist,
8604 doc: /* Alist of image types vs external libraries needed to display them.
8605
8606Each element is a list (IMAGE-TYPE LIBRARY...), where the car is a symbol
8607representing a supported image type, and the rest are strings giving
8608alternate filenames for the corresponding external libraries.
8609
8610Emacs tries to load the libraries in the order they appear on the
8611list; if none is loaded, the running session of Emacs won't
8612support the image type. Types 'pbm and 'xbm don't need to be
3046a84b 8613listed; they are always supported. */);
2a611c1a
JB
8614 Vimage_library_alist = Qnil;
8615 Fput (intern ("image-library-alist"), Qrisky_local_variable, Qt);
8616
f1f25b99 8617 DEFVAR_LISP ("max-image-size", &Vmax_image_size,
7df4765a
KS
8618 doc: /* Maximum size of images.
8619Emacs will not load an image into memory if its pixel width or
8620pixel height exceeds this limit.
8621
8622If the value is an integer, it directly specifies the maximum
8623image height and width, measured in pixels. If it is a floating
8624point number, it specifies the maximum image height and width
8625as a ratio to the frame height and width. If the value is
8626non-numeric, there is no explicit limit on the size of images. */);
f1f25b99
CY
8627 Vmax_image_size = make_float (MAX_IMAGE_SIZE);
8628
0855eb52
JB
8629 Vimage_type_cache = Qnil;
8630 staticpro (&Vimage_type_cache);
8631
7c4e3a32
RS
8632 Qpbm = intern ("pbm");
8633 staticpro (&Qpbm);
5fc9fdeb 8634 ADD_IMAGE_TYPE (Qpbm);
7c4e3a32
RS
8635
8636 Qxbm = intern ("xbm");
8637 staticpro (&Qxbm);
5fc9fdeb 8638 ADD_IMAGE_TYPE (Qxbm);
7c4e3a32
RS
8639
8640 define_image_type (&xbm_type, 1);
8641 define_image_type (&pbm_type, 1);
8642
e047f448
SM
8643 Qcount = intern ("count");
8644 staticpro (&Qcount);
8645
4ef0d4d0
KS
8646 QCascent = intern (":ascent");
8647 staticpro (&QCascent);
8648 QCmargin = intern (":margin");
8649 staticpro (&QCmargin);
8650 QCrelief = intern (":relief");
8651 staticpro (&QCrelief);
8652 QCconversion = intern (":conversion");
8653 staticpro (&QCconversion);
8654 QCcolor_symbols = intern (":color-symbols");
8655 staticpro (&QCcolor_symbols);
8656 QCheuristic_mask = intern (":heuristic-mask");
8657 staticpro (&QCheuristic_mask);
8658 QCindex = intern (":index");
8659 staticpro (&QCindex);
8660 QCmatrix = intern (":matrix");
8661 staticpro (&QCmatrix);
8662 QCcolor_adjustment = intern (":color-adjustment");
8663 staticpro (&QCcolor_adjustment);
8664 QCmask = intern (":mask");
8665 staticpro (&QCmask);
8666
8667 Qlaplace = intern ("laplace");
8668 staticpro (&Qlaplace);
8669 Qemboss = intern ("emboss");
8670 staticpro (&Qemboss);
8671 Qedge_detection = intern ("edge-detection");
8672 staticpro (&Qedge_detection);
8673 Qheuristic = intern ("heuristic");
8674 staticpro (&Qheuristic);
4ef0d4d0
KS
8675
8676 Qpostscript = intern ("postscript");
8677 staticpro (&Qpostscript);
8678#ifdef HAVE_GHOSTSCRIPT
5fc9fdeb 8679 ADD_IMAGE_TYPE (Qpostscript);
4ef0d4d0
KS
8680 QCloader = intern (":loader");
8681 staticpro (&QCloader);
8682 QCbounding_box = intern (":bounding-box");
8683 staticpro (&QCbounding_box);
8684 QCpt_width = intern (":pt-width");
8685 staticpro (&QCpt_width);
8686 QCpt_height = intern (":pt-height");
8687 staticpro (&QCpt_height);
8688#endif /* HAVE_GHOSTSCRIPT */
8689
9e2a2647 8690#if defined (HAVE_XPM) || defined (HAVE_NS)
4ef0d4d0
KS
8691 Qxpm = intern ("xpm");
8692 staticpro (&Qxpm);
5fc9fdeb 8693 ADD_IMAGE_TYPE (Qxpm);
4ef0d4d0
KS
8694#endif
8695
9e2a2647 8696#if defined (HAVE_JPEG) || defined (HAVE_NS)
4ef0d4d0
KS
8697 Qjpeg = intern ("jpeg");
8698 staticpro (&Qjpeg);
5fc9fdeb 8699 ADD_IMAGE_TYPE (Qjpeg);
4ef0d4d0
KS
8700#endif
8701
9e2a2647 8702#if defined (HAVE_TIFF) || defined (HAVE_NS)
4ef0d4d0
KS
8703 Qtiff = intern ("tiff");
8704 staticpro (&Qtiff);
5fc9fdeb 8705 ADD_IMAGE_TYPE (Qtiff);
4ef0d4d0
KS
8706#endif
8707
9e2a2647 8708#if defined (HAVE_GIF) || defined (HAVE_NS)
4ef0d4d0
KS
8709 Qgif = intern ("gif");
8710 staticpro (&Qgif);
5fc9fdeb 8711 ADD_IMAGE_TYPE (Qgif);
4ef0d4d0
KS
8712#endif
8713
9e2a2647 8714#if defined (HAVE_PNG) || defined (HAVE_NS)
4ef0d4d0
KS
8715 Qpng = intern ("png");
8716 staticpro (&Qpng);
5fc9fdeb 8717 ADD_IMAGE_TYPE (Qpng);
4ef0d4d0
KS
8718#endif
8719
4ab27a43
GM
8720#if defined (HAVE_RSVG)
8721 Qsvg = intern ("svg");
8722 staticpro (&Qsvg);
5fc9fdeb
JR
8723 ADD_IMAGE_TYPE (Qsvg);
8724#ifdef HAVE_NTGUI
df23bf08 8725 /* Other libraries used directly by svg code. */
5fc9fdeb
JR
8726 Qgdk_pixbuf = intern ("gdk-pixbuf");
8727 staticpro (&Qgdk_pixbuf);
8728 Qglib = intern ("glib");
8729 staticpro (&Qglib);
df23bf08
JR
8730 Qgobject = intern ("gobject");
8731 staticpro (&Qgobject);
5fc9fdeb
JR
8732#endif /* HAVE_NTGUI */
8733#endif /* HAVE_RSVG */
4ab27a43 8734
0855eb52 8735 defsubr (&Sinit_image_library);
4ef0d4d0 8736 defsubr (&Sclear_image_cache);
483e7ae0 8737 defsubr (&Simage_refresh);
4ef0d4d0
KS
8738 defsubr (&Simage_size);
8739 defsubr (&Simage_mask_p);
6ac3c7bb 8740 defsubr (&Simage_extension_data);
4ef0d4d0
KS
8741
8742#if GLYPH_DEBUG
8743 defsubr (&Simagep);
8744 defsubr (&Slookup_image);
8745#endif
8746
8747 DEFVAR_BOOL ("cross-disabled-images", &cross_disabled_images,
8748 doc: /* Non-nil means always draw a cross over disabled images.
3046a84b 8749Disabled images are those having a `:conversion disabled' property.
4ef0d4d0
KS
8750A cross is always drawn on black & white displays. */);
8751 cross_disabled_images = 0;
8752
8753 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
8754 doc: /* List of directories to search for window system bitmap files. */);
8755 Vx_bitmap_file_path = decode_env_path ((char *) 0, PATH_BITMAPS);
8756
8757 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
8758 doc: /* Time after which cached images are removed from the cache.
8759When an image has not been displayed this many seconds, remove it
8760from the image cache. Value must be an integer or nil with nil
8761meaning don't clear the cache. */);
8762 Vimage_cache_eviction_delay = make_number (30 * 60);
8763}
8764
4ef0d4d0
KS
8765void
8766init_image ()
8767{
4ef0d4d0
KS
8768}
8769
1b9f8cec
MB
8770/* arch-tag: 123c2a5e-14a8-4c53-ab95-af47d7db49b9
8771 (do not change this comment) */