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