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