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