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