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