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