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