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