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