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