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