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