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