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