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