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