aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKim F. Storm2004-03-11 00:27:13 +0000
committerKim F. Storm2004-03-11 00:27:13 +0000
commit8dd5ac07f4c0bb888746a5e39024a91b6d692a5c (patch)
treee5d63794f7914f474c2edcb06ad1607a055351a6 /src
parent79af19c40669ff1ecb67c89e6063600b811ffafe (diff)
downloademacs-8dd5ac07f4c0bb888746a5e39024a91b6d692a5c.tar.gz
emacs-8dd5ac07f4c0bb888746a5e39024a91b6d692a5c.zip
Image consolidation:
(Vx_bitmap_file_path, Vimage_cache_eviction_delay) (x_bitmap_height, x_bitmap_width, x_bitmap_pixmap) (x_reference_bitmap, x_create_bitmap_from_data) (x_create_bitmap_from_file, x_destroy_bitmap) (x_destroy_all_bitmaps, x_create_bitmap_mask) (XGetImage, XPutPixel, XGetPixel, XDestroyImage) (QCascent, QCmargin, QCrelief, QCconversion, QCcolor_symbols) (QCheuristic_mask, QCindex, QCmatrix, QCcolor_adjustment, QCmask) (Qlaplace, Qemboss, Qedge_detection, Qheuristic, Qcenter) (define_image_type, lookup_image_type, valid_image_p) (image_error, enum image_value_type, struct image_keyword) (parse_image_spec, image_spec_value, Fimage_size, Fimage_mask_p) (make_image, free_image, prepare_image_for_display, image_ascent) (four_corners_best, image_background, image_background_transparent) (x_clear_image_1, x_clear_image, x_alloc_image_color) (make_image_cache, free_image_cache, clear_image_cache) (Fclear_image_cache, postprocess_image, lookup_image, cache_image) (forall_images_in_image_cache, x_create_x_image_and_pixmap) (x_destroy_x_image, x_put_x_image, x_find_image_file, slurp_file) (find_image_fsspec, image_load_qt_1, image_load_quicktime) (init_image_func_pointer, image_load_quartz2d) (struct ct_color, init_color_table, free_color_table) (lookup_rgb_color, lookup_pixel_color, colors_in_color_table) (cross_disabled_images, x_to_xcolors, x_from_xcolors) (x_detect_edges, x_emboss, x_laplace, x_edge_detection) (x_disable_image, x_build_heuristic_mask) (XBM support, XPM support, PBM support, PNG support, JPEG support) (TIFF support, GIF support, Ghostscript support): Merge with image code from xfns.c and macfns.c into image.c. (syms_of_xfns): Move image related symbols to image.c. (init_external_image_libraries, init_xfns): Remove; initialization moved to init_image in image.c.
Diffstat (limited to 'src')
-rw-r--r--src/macfns.c5928
1 files changed, 0 insertions, 5928 deletions
diff --git a/src/macfns.c b/src/macfns.c
index 1b854489480..a9dcdc5e85a 100644
--- a/src/macfns.c
+++ b/src/macfns.c
@@ -117,10 +117,6 @@ static int mac_in_use;
117 117
118Lisp_Object Vx_no_window_manager; 118Lisp_Object Vx_no_window_manager;
119 119
120/* Search path for bitmap files. */
121
122Lisp_Object Vx_bitmap_file_path;
123
124/* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */ 120/* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */
125 121
126Lisp_Object Vx_pixel_size_width_font_regexp; 122Lisp_Object Vx_pixel_size_width_font_regexp;
@@ -163,7 +159,6 @@ Lisp_Object Vx_pixel_size_width_font_regexp;
163Lisp_Object Qnone; 159Lisp_Object Qnone;
164Lisp_Object Qsuppress_icon; 160Lisp_Object Qsuppress_icon;
165Lisp_Object Qundefined_color; 161Lisp_Object Qundefined_color;
166Lisp_Object Qcenter;
167Lisp_Object Qcancel_timer; 162Lisp_Object Qcancel_timer;
168Lisp_Object Qhyper; 163Lisp_Object Qhyper;
169Lisp_Object Qsuper; 164Lisp_Object Qsuper;
@@ -321,303 +316,7 @@ x_window_to_frame (dpyinfo, wdesc)
321} 316}
322 317
323 318
324
325/* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
326 id, which is just an int that this section returns. Bitmaps are
327 reference counted so they can be shared among frames.
328
329 Bitmap indices are guaranteed to be > 0, so a negative number can
330 be used to indicate no bitmap.
331
332 If you use x_create_bitmap_from_data, then you must keep track of
333 the bitmaps yourself. That is, creating a bitmap from the same
334 data more than once will not be caught. */
335
336
337/* Functions to access the contents of a bitmap, given an id. */
338
339int
340x_bitmap_height (f, id)
341 FRAME_PTR f;
342 int id;
343{
344 return FRAME_MAC_DISPLAY_INFO (f)->bitmaps[id - 1].height;
345}
346
347int
348x_bitmap_width (f, id)
349 FRAME_PTR f;
350 int id;
351{
352 return FRAME_MAC_DISPLAY_INFO (f)->bitmaps[id - 1].width;
353}
354
355#if 0 /* MAC_TODO : not used anywhere (?) */
356int
357x_bitmap_pixmap (f, id)
358 FRAME_PTR f;
359 int id;
360{
361 return (int) FRAME_MAC_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
362}
363#endif
364
365/* Allocate a new bitmap record. Returns index of new record. */
366
367static int
368x_allocate_bitmap_record (f)
369 FRAME_PTR f;
370{
371 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
372 int i;
373
374 if (dpyinfo->bitmaps == NULL)
375 {
376 dpyinfo->bitmaps_size = 10;
377 dpyinfo->bitmaps = (struct mac_bitmap_record *)
378 xmalloc (dpyinfo->bitmaps_size * sizeof (struct mac_bitmap_record));
379 dpyinfo->bitmaps_last = 1;
380 return 1;
381 }
382
383 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
384 return ++dpyinfo->bitmaps_last;
385
386 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
387 if (dpyinfo->bitmaps[i].refcount == 0)
388 return i + 1;
389
390 dpyinfo->bitmaps_size *= 2;
391 dpyinfo->bitmaps = (struct mac_bitmap_record *)
392 xrealloc (dpyinfo->bitmaps,
393 dpyinfo->bitmaps_size * sizeof (struct mac_bitmap_record));
394 return ++dpyinfo->bitmaps_last;
395}
396
397/* Add one reference to the reference count of the bitmap with id
398 ID. */
399
400void
401x_reference_bitmap (f, id)
402 FRAME_PTR f;
403 int id;
404{
405 ++FRAME_MAC_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
406}
407
408/* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at
409 BITS. */
410
411int
412x_create_bitmap_from_data (f, bits, width, height)
413 struct frame *f;
414 char *bits;
415 unsigned int width, height;
416{
417 struct x_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
418 int id;
419
420 /* MAC_TODO: for now fail if width is not mod 16 (toolbox requires it) */
421
422 id = x_allocate_bitmap_record (f);
423
424 if (width % 16 != 0)
425 return -1;
426
427 dpyinfo->bitmaps[id - 1].bitmap_data = (char *) xmalloc (height * width);
428 if (! dpyinfo->bitmaps[id - 1].bitmap_data)
429 return -1;
430
431 bcopy (bits, dpyinfo->bitmaps[id - 1].bitmap_data, height * width);
432
433 dpyinfo->bitmaps[id - 1].refcount = 1;
434 dpyinfo->bitmaps[id - 1].height = height;
435 dpyinfo->bitmaps[id - 1].width = width;
436
437 return id;
438}
439
440/* Create bitmap from file FILE for frame F. */
441
442int
443x_create_bitmap_from_file (f, file)
444 struct frame *f;
445 Lisp_Object file;
446{
447 return -1;
448#if 0 /* MAC_TODO : bitmap support */
449 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
450 unsigned int width, height;
451 HBITMAP bitmap;
452 int xhot, yhot, result, id;
453 Lisp_Object found;
454 int fd;
455 char *filename;
456 HINSTANCE hinst;
457
458 /* Look for an existing bitmap with the same name. */
459 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
460 {
461 if (dpyinfo->bitmaps[id].refcount
462 && dpyinfo->bitmaps[id].file
463 && !strcmp (dpyinfo->bitmaps[id].file, (char *) SDATA (file)))
464 {
465 ++dpyinfo->bitmaps[id].refcount;
466 return id + 1;
467 }
468 }
469
470 /* Search bitmap-file-path for the file, if appropriate. */
471 fd = openp (Vx_bitmap_file_path, file, "", &found, Qnil);
472 if (fd < 0)
473 return -1;
474 /* LoadLibraryEx won't handle special files handled by Emacs handler. */
475 if (fd == 0)
476 return -1;
477 emacs_close (fd);
478
479 filename = (char *) SDATA (found);
480
481 hinst = LoadLibraryEx (filename, NULL, LOAD_LIBRARY_AS_DATAFILE);
482
483 if (hinst == NULL)
484 return -1;
485
486
487 result = XReadBitmapFile (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
488 filename, &width, &height, &bitmap, &xhot, &yhot);
489 if (result != BitmapSuccess)
490 return -1;
491
492 id = x_allocate_bitmap_record (f);
493 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
494 dpyinfo->bitmaps[id - 1].refcount = 1;
495 dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (SCHARS (file) + 1);
496 dpyinfo->bitmaps[id - 1].depth = 1;
497 dpyinfo->bitmaps[id - 1].height = height;
498 dpyinfo->bitmaps[id - 1].width = width;
499 strcpy (dpyinfo->bitmaps[id - 1].file, SDATA (file));
500
501 return id;
502#endif /* MAC_TODO */
503}
504
505/* Remove reference to bitmap with id number ID. */
506
507void
508x_destroy_bitmap (f, id)
509 FRAME_PTR f;
510 int id;
511{
512 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
513
514 if (id > 0)
515 {
516 --dpyinfo->bitmaps[id - 1].refcount;
517 if (dpyinfo->bitmaps[id - 1].refcount == 0)
518 {
519 BLOCK_INPUT;
520 dpyinfo->bitmaps[id - 1].bitmap_data = NULL;
521 UNBLOCK_INPUT;
522 }
523 }
524}
525
526/* Free all the bitmaps for the display specified by DPYINFO. */
527
528static void
529x_destroy_all_bitmaps (dpyinfo)
530 struct mac_display_info *dpyinfo;
531{
532 int i;
533 for (i = 0; i < dpyinfo->bitmaps_last; i++)
534 if (dpyinfo->bitmaps[i].refcount > 0)
535 xfree (dpyinfo->bitmaps[i].bitmap_data);
536 dpyinfo->bitmaps_last = 0;
537}
538
539
540
541/* Mac equivalent of XImage. */
542typedef Pixmap XImagePtr;
543#define ZPixmap 0 /* arbitrary */
544
545static XImagePtr
546XGetImage (display, pixmap, x, y, width, height, plane_mask, format)
547 Display *display; /* not used */
548 Pixmap pixmap;
549 int x, y; /* not used */
550 unsigned int width, height; /* not used */
551 unsigned long plane_mask; /* not used */
552 int format; /* not used */
553{
554#if GLYPH_DEBUG
555 xassert (x == 0 && y == 0);
556 {
557 Rect ri, rp;
558 SetRect (&ri, 0, 0, width, height);
559 xassert (EqualRect (&ri, GetPixBounds (GetGWorldPixMap (pixmap), &rp)));
560 }
561 xassert (! (pixelsLocked & GetPixelsState (GetGWorldPixMap (pixmap))));
562#endif
563
564 LockPixels (GetGWorldPixMap (pixmap));
565
566 return pixmap;
567}
568
569static void
570XPutPixel (ximage, x, y, pixel)
571 XImagePtr ximage;
572 int x, y;
573 unsigned long pixel;
574{
575 RGBColor color;
576
577 SetGWorld (ximage, NULL);
578
579 color.red = RED16_FROM_ULONG (pixel);
580 color.green = GREEN16_FROM_ULONG (pixel);
581 color.blue = BLUE16_FROM_ULONG (pixel);
582 SetCPixel (x, y, &color);
583}
584
585static unsigned long
586XGetPixel (ximage, x, y)
587 XImagePtr ximage;
588 int x, y;
589{
590 RGBColor color;
591
592 SetGWorld (ximage, NULL);
593
594 GetCPixel (x, y, &color);
595 return RGB_TO_ULONG (color.red >> 8, color.green >> 8, color.blue >> 8);
596}
597
598static void
599XDestroyImage (ximg)
600 XImagePtr ximg;
601{
602 UnlockPixels (GetGWorldPixMap (ximg));
603}
604
605
606
607/* Useful functions defined in the section
608 `Image type independent image structures' below. */
609
610static unsigned long four_corners_best P_ ((XImagePtr ximg, unsigned long width,
611 unsigned long height));
612
613static int x_create_x_image_and_pixmap P_ ((struct frame *f, int width, int height,
614 int depth, XImagePtr *ximg,
615 Pixmap *pixmap));
616
617static void x_destroy_x_image P_ ((XImagePtr ximg));
618
619static Lisp_Object unwind_create_frame P_ ((Lisp_Object)); 319static Lisp_Object unwind_create_frame P_ ((Lisp_Object));
620static void x_disable_image P_ ((struct frame *, struct image *));
621 320
622void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object)); 321void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
623void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object)); 322void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
@@ -640,14 +339,6 @@ static Lisp_Object x_default_scroll_bar_color_parameter P_ ((struct frame *,
640 Lisp_Object, 339 Lisp_Object,
641 char *, char *, 340 char *, char *,
642 int)); 341 int));
643static void x_edge_detection P_ ((struct frame *, struct image *, Lisp_Object,
644 Lisp_Object));
645static void init_color_table P_ ((void));
646static void free_color_table P_ ((void));
647static unsigned long *colors_in_color_table P_ ((int *n));
648static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
649static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
650
651/* Store the screen positions of frame F into XPTR and YPTR. 342/* Store the screen positions of frame F into XPTR and YPTR.
652 These are the positions of the containing window manager window, 343 These are the positions of the containing window manager window,
653 not Emacs's own window. */ 344 not Emacs's own window. */
@@ -3611,5488 +3302,6 @@ If DISPLAY is omitted or nil, that stands for the selected frame's display. */)
3611 return Qnil; 3302 return Qnil;
3612} 3303}
3613 3304
3614
3615
3616/***********************************************************************
3617 Image types
3618 ***********************************************************************/
3619
3620/* Value is the number of elements of vector VECTOR. */
3621
3622#define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
3623
3624/* List of supported image types. Use define_image_type to add new
3625 types. Use lookup_image_type to find a type for a given symbol. */
3626
3627static struct image_type *image_types;
3628
3629/* The symbol `xbm' which is used as the type symbol for XBM images. */
3630
3631Lisp_Object Qxbm;
3632
3633/* Keywords. */
3634
3635extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
3636extern Lisp_Object QCdata, QCtype;
3637Lisp_Object QCascent, QCmargin, QCrelief;
3638Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
3639Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
3640
3641/* Other symbols. */
3642
3643Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
3644
3645/* Time in seconds after which images should be removed from the cache
3646 if not displayed. */
3647
3648Lisp_Object Vimage_cache_eviction_delay;
3649
3650/* Function prototypes. */
3651
3652static void define_image_type P_ ((struct image_type *type));
3653static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
3654static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
3655static void x_laplace P_ ((struct frame *, struct image *));
3656static void x_emboss P_ ((struct frame *, struct image *));
3657static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
3658 Lisp_Object));
3659
3660
3661/* Define a new image type from TYPE. This adds a copy of TYPE to
3662 image_types and adds the symbol *TYPE->type to Vimage_types. */
3663
3664static void
3665define_image_type (type)
3666 struct image_type *type;
3667{
3668 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
3669 The initialized data segment is read-only. */
3670 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
3671 bcopy (type, p, sizeof *p);
3672 p->next = image_types;
3673 image_types = p;
3674 Vimage_types = Fcons (*p->type, Vimage_types);
3675}
3676
3677
3678/* Look up image type SYMBOL, and return a pointer to its image_type
3679 structure. Value is null if SYMBOL is not a known image type. */
3680
3681static INLINE struct image_type *
3682lookup_image_type (symbol)
3683 Lisp_Object symbol;
3684{
3685 struct image_type *type;
3686
3687 for (type = image_types; type; type = type->next)
3688 if (EQ (symbol, *type->type))
3689 break;
3690
3691 return type;
3692}
3693
3694
3695/* Value is non-zero if OBJECT is a valid Lisp image specification. A
3696 valid image specification is a list whose car is the symbol
3697 `image', and whose rest is a property list. The property list must
3698 contain a value for key `:type'. That value must be the name of a
3699 supported image type. The rest of the property list depends on the
3700 image type. */
3701
3702int
3703valid_image_p (object)
3704 Lisp_Object object;
3705{
3706 int valid_p = 0;
3707
3708 if (IMAGEP (object))
3709 {
3710 Lisp_Object tem;
3711
3712 for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem))
3713 if (EQ (XCAR (tem), QCtype))
3714 {
3715 tem = XCDR (tem);
3716 if (CONSP (tem) && SYMBOLP (XCAR (tem)))
3717 {
3718 struct image_type *type;
3719 type = lookup_image_type (XCAR (tem));
3720 if (type)
3721 valid_p = type->valid_p (object);
3722 }
3723
3724 break;
3725 }
3726 }
3727
3728 return valid_p;
3729}
3730
3731
3732/* Log error message with format string FORMAT and argument ARG.
3733 Signaling an error, e.g. when an image cannot be loaded, is not a
3734 good idea because this would interrupt redisplay, and the error
3735 message display would lead to another redisplay. This function
3736 therefore simply displays a message. */
3737
3738static void
3739image_error (format, arg1, arg2)
3740 char *format;
3741 Lisp_Object arg1, arg2;
3742{
3743 add_to_log (format, arg1, arg2);
3744}
3745
3746
3747
3748/***********************************************************************
3749 Image specifications
3750 ***********************************************************************/
3751
3752enum image_value_type
3753{
3754 IMAGE_DONT_CHECK_VALUE_TYPE,
3755 IMAGE_STRING_VALUE,
3756 IMAGE_STRING_OR_NIL_VALUE,
3757 IMAGE_SYMBOL_VALUE,
3758 IMAGE_POSITIVE_INTEGER_VALUE,
3759 IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
3760 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
3761 IMAGE_ASCENT_VALUE,
3762 IMAGE_INTEGER_VALUE,
3763 IMAGE_FUNCTION_VALUE,
3764 IMAGE_NUMBER_VALUE,
3765 IMAGE_BOOL_VALUE
3766};
3767
3768/* Structure used when parsing image specifications. */
3769
3770struct image_keyword
3771{
3772 /* Name of keyword. */
3773 char *name;
3774
3775 /* The type of value allowed. */
3776 enum image_value_type type;
3777
3778 /* Non-zero means key must be present. */
3779 int mandatory_p;
3780
3781 /* Used to recognize duplicate keywords in a property list. */
3782 int count;
3783
3784 /* The value that was found. */
3785 Lisp_Object value;
3786};
3787
3788
3789static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
3790 int, Lisp_Object));
3791static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
3792
3793
3794/* Parse image spec SPEC according to KEYWORDS. A valid image spec
3795 has the format (image KEYWORD VALUE ...). One of the keyword/
3796 value pairs must be `:type TYPE'. KEYWORDS is a vector of
3797 image_keywords structures of size NKEYWORDS describing other
3798 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
3799
3800static int
3801parse_image_spec (spec, keywords, nkeywords, type)
3802 Lisp_Object spec;
3803 struct image_keyword *keywords;
3804 int nkeywords;
3805 Lisp_Object type;
3806{
3807 int i;
3808 Lisp_Object plist;
3809
3810 if (!IMAGEP (spec))
3811 return 0;
3812
3813 plist = XCDR (spec);
3814 while (CONSP (plist))
3815 {
3816 Lisp_Object key, value;
3817
3818 /* First element of a pair must be a symbol. */
3819 key = XCAR (plist);
3820 plist = XCDR (plist);
3821 if (!SYMBOLP (key))
3822 return 0;
3823
3824 /* There must follow a value. */
3825 if (!CONSP (plist))
3826 return 0;
3827 value = XCAR (plist);
3828 plist = XCDR (plist);
3829
3830 /* Find key in KEYWORDS. Error if not found. */
3831 for (i = 0; i < nkeywords; ++i)
3832 if (strcmp (keywords[i].name, SDATA (SYMBOL_NAME (key))) == 0)
3833 break;
3834
3835 if (i == nkeywords)
3836 continue;
3837
3838 /* Record that we recognized the keyword. If a keywords
3839 was found more than once, it's an error. */
3840 keywords[i].value = value;
3841 ++keywords[i].count;
3842
3843 if (keywords[i].count > 1)
3844 return 0;
3845
3846 /* Check type of value against allowed type. */
3847 switch (keywords[i].type)
3848 {
3849 case IMAGE_STRING_VALUE:
3850 if (!STRINGP (value))
3851 return 0;
3852 break;
3853
3854 case IMAGE_STRING_OR_NIL_VALUE:
3855 if (!STRINGP (value) && !NILP (value))
3856 return 0;
3857 break;
3858
3859 case IMAGE_SYMBOL_VALUE:
3860 if (!SYMBOLP (value))
3861 return 0;
3862 break;
3863
3864 case IMAGE_POSITIVE_INTEGER_VALUE:
3865 if (!INTEGERP (value) || XINT (value) <= 0)
3866 return 0;
3867 break;
3868
3869 case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
3870 if (INTEGERP (value) && XINT (value) >= 0)
3871 break;
3872 if (CONSP (value)
3873 && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
3874 && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
3875 break;
3876 return 0;
3877
3878 case IMAGE_ASCENT_VALUE:
3879 if (SYMBOLP (value) && EQ (value, Qcenter))
3880 break;
3881 else if (INTEGERP (value)
3882 && XINT (value) >= 0
3883 && XINT (value) <= 100)
3884 break;
3885 return 0;
3886
3887 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
3888 if (!INTEGERP (value) || XINT (value) < 0)
3889 return 0;
3890 break;
3891
3892 case IMAGE_DONT_CHECK_VALUE_TYPE:
3893 break;
3894
3895 case IMAGE_FUNCTION_VALUE:
3896 value = indirect_function (value);
3897 if (SUBRP (value)
3898 || COMPILEDP (value)
3899 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
3900 break;
3901 return 0;
3902
3903 case IMAGE_NUMBER_VALUE:
3904 if (!INTEGERP (value) && !FLOATP (value))
3905 return 0;
3906 break;
3907
3908 case IMAGE_INTEGER_VALUE:
3909 if (!INTEGERP (value))
3910 return 0;
3911 break;
3912
3913 case IMAGE_BOOL_VALUE:
3914 if (!NILP (value) && !EQ (value, Qt))
3915 return 0;
3916 break;
3917
3918 default:
3919 abort ();
3920 break;
3921 }
3922
3923 if (EQ (key, QCtype) && !EQ (type, value))
3924 return 0;
3925 }
3926
3927 /* Check that all mandatory fields are present. */
3928 for (i = 0; i < nkeywords; ++i)
3929 if (keywords[i].mandatory_p && keywords[i].count == 0)
3930 return 0;
3931
3932 return NILP (plist);
3933}
3934
3935
3936/* Return the value of KEY in image specification SPEC. Value is nil
3937 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
3938 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
3939
3940static Lisp_Object
3941image_spec_value (spec, key, found)
3942 Lisp_Object spec, key;
3943 int *found;
3944{
3945 Lisp_Object tail;
3946
3947 xassert (valid_image_p (spec));
3948
3949 for (tail = XCDR (spec);
3950 CONSP (tail) && CONSP (XCDR (tail));
3951 tail = XCDR (XCDR (tail)))
3952 {
3953 if (EQ (XCAR (tail), key))
3954 {
3955 if (found)
3956 *found = 1;
3957 return XCAR (XCDR (tail));
3958 }
3959 }
3960
3961 if (found)
3962 *found = 0;
3963 return Qnil;
3964}
3965
3966
3967DEFUN ("image-size", Fimage_size, Simage_size, 1, 3, 0,
3968 doc: /* Return the size of image SPEC as pair (WIDTH . HEIGHT).
3969PIXELS non-nil means return the size in pixels, otherwise return the
3970size in canonical character units.
3971FRAME is the frame on which the image will be displayed. FRAME nil
3972or omitted means use the selected frame. */)
3973 (spec, pixels, frame)
3974 Lisp_Object spec, pixels, frame;
3975{
3976 Lisp_Object size;
3977
3978 size = Qnil;
3979 if (valid_image_p (spec))
3980 {
3981 struct frame *f = check_x_frame (frame);
3982 int id = lookup_image (f, spec);
3983 struct image *img = IMAGE_FROM_ID (f, id);
3984 int width = img->width + 2 * img->hmargin;
3985 int height = img->height + 2 * img->vmargin;
3986
3987 if (NILP (pixels))
3988 size = Fcons (make_float ((double) width / FRAME_COLUMN_WIDTH (f)),
3989 make_float ((double) height / FRAME_LINE_HEIGHT (f)));
3990 else
3991 size = Fcons (make_number (width), make_number (height));
3992 }
3993 else
3994 error ("Invalid image specification");
3995
3996 return size;
3997}
3998
3999
4000DEFUN ("image-mask-p", Fimage_mask_p, Simage_mask_p, 1, 2, 0,
4001 doc: /* Return t if image SPEC has a mask bitmap.
4002FRAME is the frame on which the image will be displayed. FRAME nil
4003or omitted means use the selected frame. */)
4004 (spec, frame)
4005 Lisp_Object spec, frame;
4006{
4007 Lisp_Object mask;
4008
4009 mask = Qnil;
4010 if (valid_image_p (spec))
4011 {
4012 struct frame *f = check_x_frame (frame);
4013 int id = lookup_image (f, spec);
4014 struct image *img = IMAGE_FROM_ID (f, id);
4015 if (img->mask)
4016 mask = Qt;
4017 }
4018 else
4019 error ("Invalid image specification");
4020
4021 return mask;
4022}
4023
4024
4025
4026/***********************************************************************
4027 Image type independent image structures
4028 ***********************************************************************/
4029
4030static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
4031static void free_image P_ ((struct frame *f, struct image *img));
4032
4033
4034/* Allocate and return a new image structure for image specification
4035 SPEC. SPEC has a hash value of HASH. */
4036
4037static struct image *
4038make_image (spec, hash)
4039 Lisp_Object spec;
4040 unsigned hash;
4041{
4042 struct image *img = (struct image *) xmalloc (sizeof *img);
4043
4044 xassert (valid_image_p (spec));
4045 bzero (img, sizeof *img);
4046 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
4047 xassert (img->type != NULL);
4048 img->spec = spec;
4049 img->data.lisp_val = Qnil;
4050 img->ascent = DEFAULT_IMAGE_ASCENT;
4051 img->hash = hash;
4052 return img;
4053}
4054
4055
4056/* Free image IMG which was used on frame F, including its resources. */
4057
4058static void
4059free_image (f, img)
4060 struct frame *f;
4061 struct image *img;
4062{
4063 if (img)
4064 {
4065 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
4066
4067 /* Remove IMG from the hash table of its cache. */
4068 if (img->prev)
4069 img->prev->next = img->next;
4070 else
4071 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
4072
4073 if (img->next)
4074 img->next->prev = img->prev;
4075
4076 c->images[img->id] = NULL;
4077
4078 /* Free resources, then free IMG. */
4079 img->type->free (f, img);
4080 xfree (img);
4081 }
4082}
4083
4084
4085/* Prepare image IMG for display on frame F. Must be called before
4086 drawing an image. */
4087
4088void
4089prepare_image_for_display (f, img)
4090 struct frame *f;
4091 struct image *img;
4092{
4093 EMACS_TIME t;
4094
4095 /* We're about to display IMG, so set its timestamp to `now'. */
4096 EMACS_GET_TIME (t);
4097 img->timestamp = EMACS_SECS (t);
4098
4099 /* If IMG doesn't have a pixmap yet, load it now, using the image
4100 type dependent loader function. */
4101 if (img->pixmap == 0 && !img->load_failed_p)
4102 img->load_failed_p = img->type->load (f, img) == 0;
4103}
4104
4105
4106/* Value is the number of pixels for the ascent of image IMG when
4107 drawn in face FACE. */
4108
4109int
4110image_ascent (img, face)
4111 struct image *img;
4112 struct face *face;
4113{
4114 int height = img->height + img->vmargin;
4115 int ascent;
4116
4117 if (img->ascent == CENTERED_IMAGE_ASCENT)
4118 {
4119 if (face->font)
4120 /* This expression is arranged so that if the image can't be
4121 exactly centered, it will be moved slightly up. This is
4122 because a typical font is `top-heavy' (due to the presence
4123 uppercase letters), so the image placement should err towards
4124 being top-heavy too. It also just generally looks better. */
4125 ascent = (height + face->font->ascent - face->font->descent + 1) / 2;
4126 else
4127 ascent = height / 2;
4128 }
4129 else
4130 ascent = height * img->ascent / 100.0;
4131
4132 return ascent;
4133}
4134
4135
4136/* Image background colors. */
4137
4138static unsigned long
4139four_corners_best (ximg, width, height)
4140 XImagePtr ximg;
4141 unsigned long width, height;
4142{
4143 unsigned long corners[4], best;
4144 int i, best_count;
4145
4146 /* Get the colors at the corners of ximg. */
4147 corners[0] = XGetPixel (ximg, 0, 0);
4148 corners[1] = XGetPixel (ximg, width - 1, 0);
4149 corners[2] = XGetPixel (ximg, width - 1, height - 1);
4150 corners[3] = XGetPixel (ximg, 0, height - 1);
4151
4152 /* Choose the most frequently found color as background. */
4153 for (i = best_count = 0; i < 4; ++i)
4154 {
4155 int j, n;
4156
4157 for (j = n = 0; j < 4; ++j)
4158 if (corners[i] == corners[j])
4159 ++n;
4160
4161 if (n > best_count)
4162 best = corners[i], best_count = n;
4163 }
4164
4165 return best;
4166}
4167
4168/* Return the `background' field of IMG. If IMG doesn't have one yet,
4169 it is guessed heuristically. If non-zero, XIMG is an existing XImage
4170 object to use for the heuristic. */
4171
4172unsigned long
4173image_background (img, f, ximg)
4174 struct image *img;
4175 struct frame *f;
4176 XImagePtr ximg;
4177{
4178 if (! img->background_valid)
4179 /* IMG doesn't have a background yet, try to guess a reasonable value. */
4180 {
4181 int free_ximg = !ximg;
4182
4183 if (! ximg)
4184 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
4185 0, 0, img->width, img->height, ~0, ZPixmap);
4186
4187 img->background = four_corners_best (ximg, img->width, img->height);
4188
4189 if (free_ximg)
4190 XDestroyImage (ximg);
4191
4192 img->background_valid = 1;
4193 }
4194
4195 return img->background;
4196}
4197
4198/* Return the `background_transparent' field of IMG. If IMG doesn't
4199 have one yet, it is guessed heuristically. If non-zero, MASK is an
4200 existing XImage object to use for the heuristic. */
4201
4202int
4203image_background_transparent (img, f, mask)
4204 struct image *img;
4205 struct frame *f;
4206 XImagePtr mask;
4207{
4208 if (! img->background_transparent_valid)
4209 /* IMG doesn't have a background yet, try to guess a reasonable value. */
4210 {
4211 if (img->mask)
4212 {
4213 int free_mask = !mask;
4214
4215 if (! mask)
4216 mask = XGetImage (FRAME_X_DISPLAY (f), img->mask,
4217 0, 0, img->width, img->height, ~0, ZPixmap);
4218
4219 img->background_transparent
4220 = four_corners_best (mask, img->width, img->height) == PIX_MASK_RETAIN (f);
4221
4222 if (free_mask)
4223 XDestroyImage (mask);
4224 }
4225 else
4226 img->background_transparent = 0;
4227
4228 img->background_transparent_valid = 1;
4229 }
4230
4231 return img->background_transparent;
4232}
4233
4234
4235/***********************************************************************
4236 Helper functions for X image types
4237 ***********************************************************************/
4238
4239static void x_clear_image_1 P_ ((struct frame *, struct image *, int,
4240 int, int));
4241static void x_clear_image P_ ((struct frame *f, struct image *img));
4242static unsigned long x_alloc_image_color P_ ((struct frame *f,
4243 struct image *img,
4244 Lisp_Object color_name,
4245 unsigned long dflt));
4246
4247
4248/* Clear X resources of image IMG on frame F. PIXMAP_P non-zero means
4249 free the pixmap if any. MASK_P non-zero means clear the mask
4250 pixmap if any. COLORS_P non-zero means free colors allocated for
4251 the image, if any. */
4252
4253static void
4254x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p)
4255 struct frame *f;
4256 struct image *img;
4257 int pixmap_p, mask_p, colors_p;
4258{
4259 if (pixmap_p && img->pixmap)
4260 {
4261 XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap);
4262 img->pixmap = NULL;
4263 img->background_valid = 0;
4264 }
4265
4266 if (mask_p && img->mask)
4267 {
4268 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
4269 img->mask = NULL;
4270 img->background_transparent_valid = 0;
4271 }
4272
4273 if (colors_p && img->ncolors)
4274 {
4275#if 0 /* TODO: color table support. */
4276 x_free_colors (f, img->colors, img->ncolors);
4277#endif
4278 xfree (img->colors);
4279 img->colors = NULL;
4280 img->ncolors = 0;
4281 }
4282}
4283
4284/* Free X resources of image IMG which is used on frame F. */
4285
4286static void
4287x_clear_image (f, img)
4288 struct frame *f;
4289 struct image *img;
4290{
4291 BLOCK_INPUT;
4292 x_clear_image_1 (f, img, 1, 1, 1);
4293 UNBLOCK_INPUT;
4294}
4295
4296
4297/* Allocate color COLOR_NAME for image IMG on frame F. If color
4298 cannot be allocated, use DFLT. Add a newly allocated color to
4299 IMG->colors, so that it can be freed again. Value is the pixel
4300 color. */
4301
4302static unsigned long
4303x_alloc_image_color (f, img, color_name, dflt)
4304 struct frame *f;
4305 struct image *img;
4306 Lisp_Object color_name;
4307 unsigned long dflt;
4308{
4309 XColor color;
4310 unsigned long result;
4311
4312 xassert (STRINGP (color_name));
4313
4314 if (mac_defined_color (f, SDATA (color_name), &color, 1))
4315 {
4316 /* This isn't called frequently so we get away with simply
4317 reallocating the color vector to the needed size, here. */
4318 ++img->ncolors;
4319 img->colors =
4320 (unsigned long *) xrealloc (img->colors,
4321 img->ncolors * sizeof *img->colors);
4322 img->colors[img->ncolors - 1] = color.pixel;
4323 result = color.pixel;
4324 }
4325 else
4326 result = dflt;
4327
4328 return result;
4329}
4330
4331
4332
4333/***********************************************************************
4334 Image Cache
4335 ***********************************************************************/
4336
4337static void cache_image P_ ((struct frame *f, struct image *img));
4338static void postprocess_image P_ ((struct frame *, struct image *));
4339
4340
4341/* Return a new, initialized image cache that is allocated from the
4342 heap. Call free_image_cache to free an image cache. */
4343
4344struct image_cache *
4345make_image_cache ()
4346{
4347 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
4348 int size;
4349
4350 bzero (c, sizeof *c);
4351 c->size = 50;
4352 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
4353 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
4354 c->buckets = (struct image **) xmalloc (size);
4355 bzero (c->buckets, size);
4356 return c;
4357}
4358
4359
4360/* Free image cache of frame F. Be aware that X frames share images
4361 caches. */
4362
4363void
4364free_image_cache (f)
4365 struct frame *f;
4366{
4367 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
4368 if (c)
4369 {
4370 int i;
4371
4372 /* Cache should not be referenced by any frame when freed. */
4373 xassert (c->refcount == 0);
4374
4375 for (i = 0; i < c->used; ++i)
4376 free_image (f, c->images[i]);
4377 xfree (c->images);
4378 xfree (c->buckets);
4379 xfree (c);
4380 FRAME_X_IMAGE_CACHE (f) = NULL;
4381 }
4382}
4383
4384
4385/* Clear image cache of frame F. FORCE_P non-zero means free all
4386 images. FORCE_P zero means clear only images that haven't been
4387 displayed for some time. Should be called from time to time to
4388 reduce the number of loaded images. If image-eviction-seconds is
4389 non-nil, this frees images in the cache which weren't displayed for
4390 at least that many seconds. */
4391
4392void
4393clear_image_cache (f, force_p)
4394 struct frame *f;
4395 int force_p;
4396{
4397 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
4398
4399 if (c && INTEGERP (Vimage_cache_eviction_delay))
4400 {
4401 EMACS_TIME t;
4402 unsigned long old;
4403 int i, nfreed;
4404
4405 EMACS_GET_TIME (t);
4406 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
4407
4408 /* Block input so that we won't be interrupted by a SIGIO
4409 while being in an inconsistent state. */
4410 BLOCK_INPUT;
4411
4412 for (i = nfreed = 0; i < c->used; ++i)
4413 {
4414 struct image *img = c->images[i];
4415 if (img != NULL
4416 && (force_p || img->timestamp < old))
4417 {
4418 free_image (f, img);
4419 ++nfreed;
4420 }
4421 }
4422
4423 /* We may be clearing the image cache because, for example,
4424 Emacs was iconified for a longer period of time. In that
4425 case, current matrices may still contain references to
4426 images freed above. So, clear these matrices. */
4427 if (nfreed)
4428 {
4429 Lisp_Object tail, frame;
4430
4431 FOR_EACH_FRAME (tail, frame)
4432 {
4433 struct frame *f = XFRAME (frame);
4434 if (FRAME_MAC_P (f)
4435 && FRAME_X_IMAGE_CACHE (f) == c)
4436 clear_current_matrices (f);
4437 }
4438
4439 ++windows_or_buffers_changed;
4440 }
4441
4442 UNBLOCK_INPUT;
4443 }
4444}
4445
4446
4447DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
4448 0, 1, 0,
4449 doc: /* Clear the image cache of FRAME.
4450FRAME nil or omitted means use the selected frame.
4451FRAME t means clear the image caches of all frames. */)
4452 (frame)
4453 Lisp_Object frame;
4454{
4455 if (EQ (frame, Qt))
4456 {
4457 Lisp_Object tail;
4458
4459 FOR_EACH_FRAME (tail, frame)
4460 if (FRAME_MAC_P (XFRAME (frame)))
4461 clear_image_cache (XFRAME (frame), 1);
4462 }
4463 else
4464 clear_image_cache (check_x_frame (frame), 1);
4465
4466 return Qnil;
4467}
4468
4469
4470/* Compute masks and transform image IMG on frame F, as specified
4471 by the image's specification, */
4472
4473static void
4474postprocess_image (f, img)
4475 struct frame *f;
4476 struct image *img;
4477{
4478 /* Manipulation of the image's mask. */
4479 if (img->pixmap)
4480 {
4481 Lisp_Object conversion, spec;
4482 Lisp_Object mask;
4483
4484 spec = img->spec;
4485
4486 /* `:heuristic-mask t'
4487 `:mask heuristic'
4488 means build a mask heuristically.
4489 `:heuristic-mask (R G B)'
4490 `:mask (heuristic (R G B))'
4491 means build a mask from color (R G B) in the
4492 image.
4493 `:mask nil'
4494 means remove a mask, if any. */
4495
4496 mask = image_spec_value (spec, QCheuristic_mask, NULL);
4497 if (!NILP (mask))
4498 x_build_heuristic_mask (f, img, mask);
4499 else
4500 {
4501 int found_p;
4502
4503 mask = image_spec_value (spec, QCmask, &found_p);
4504
4505 if (EQ (mask, Qheuristic))
4506 x_build_heuristic_mask (f, img, Qt);
4507 else if (CONSP (mask)
4508 && EQ (XCAR (mask), Qheuristic))
4509 {
4510 if (CONSP (XCDR (mask)))
4511 x_build_heuristic_mask (f, img, XCAR (XCDR (mask)));
4512 else
4513 x_build_heuristic_mask (f, img, XCDR (mask));
4514 }
4515 else if (NILP (mask) && found_p && img->mask)
4516 {
4517 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
4518 img->mask = NULL;
4519 }
4520 }
4521
4522
4523 /* Should we apply an image transformation algorithm? */
4524 conversion = image_spec_value (spec, QCconversion, NULL);
4525 if (EQ (conversion, Qdisabled))
4526 x_disable_image (f, img);
4527 else if (EQ (conversion, Qlaplace))
4528 x_laplace (f, img);
4529 else if (EQ (conversion, Qemboss))
4530 x_emboss (f, img);
4531 else if (CONSP (conversion)
4532 && EQ (XCAR (conversion), Qedge_detection))
4533 {
4534 Lisp_Object tem;
4535 tem = XCDR (conversion);
4536 if (CONSP (tem))
4537 x_edge_detection (f, img,
4538 Fplist_get (tem, QCmatrix),
4539 Fplist_get (tem, QCcolor_adjustment));
4540 }
4541 }
4542}
4543
4544
4545/* Return the id of image with Lisp specification SPEC on frame F.
4546 SPEC must be a valid Lisp image specification (see valid_image_p). */
4547
4548int
4549lookup_image (f, spec)
4550 struct frame *f;
4551 Lisp_Object spec;
4552{
4553 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
4554 struct image *img;
4555 int i;
4556 unsigned hash;
4557 struct gcpro gcpro1;
4558 EMACS_TIME now;
4559
4560 /* F must be a window-system frame, and SPEC must be a valid image
4561 specification. */
4562 xassert (FRAME_WINDOW_P (f));
4563 xassert (valid_image_p (spec));
4564
4565 GCPRO1 (spec);
4566
4567 /* Look up SPEC in the hash table of the image cache. */
4568 hash = sxhash (spec, 0);
4569 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
4570
4571 for (img = c->buckets[i]; img; img = img->next)
4572 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
4573 break;
4574
4575 /* If not found, create a new image and cache it. */
4576 if (img == NULL)
4577 {
4578 extern Lisp_Object Qpostscript;
4579
4580 BLOCK_INPUT;
4581 img = make_image (spec, hash);
4582 cache_image (f, img);
4583 img->load_failed_p = img->type->load (f, img) == 0;
4584
4585 /* If we can't load the image, and we don't have a width and
4586 height, use some arbitrary width and height so that we can
4587 draw a rectangle for it. */
4588 if (img->load_failed_p)
4589 {
4590 Lisp_Object value;
4591
4592 value = image_spec_value (spec, QCwidth, NULL);
4593 img->width = (INTEGERP (value)
4594 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
4595 value = image_spec_value (spec, QCheight, NULL);
4596 img->height = (INTEGERP (value)
4597 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
4598 }
4599 else
4600 {
4601 /* Handle image type independent image attributes
4602 `:ascent ASCENT', `:margin MARGIN', `:relief RELIEF',
4603 `:background COLOR'. */
4604 Lisp_Object ascent, margin, relief, bg;
4605
4606 ascent = image_spec_value (spec, QCascent, NULL);
4607 if (INTEGERP (ascent))
4608 img->ascent = XFASTINT (ascent);
4609 else if (EQ (ascent, Qcenter))
4610 img->ascent = CENTERED_IMAGE_ASCENT;
4611
4612 margin = image_spec_value (spec, QCmargin, NULL);
4613 if (INTEGERP (margin) && XINT (margin) >= 0)
4614 img->vmargin = img->hmargin = XFASTINT (margin);
4615 else if (CONSP (margin) && INTEGERP (XCAR (margin))
4616 && INTEGERP (XCDR (margin)))
4617 {
4618 if (XINT (XCAR (margin)) > 0)
4619 img->hmargin = XFASTINT (XCAR (margin));
4620 if (XINT (XCDR (margin)) > 0)
4621 img->vmargin = XFASTINT (XCDR (margin));
4622 }
4623
4624 relief = image_spec_value (spec, QCrelief, NULL);
4625 if (INTEGERP (relief))
4626 {
4627 img->relief = XINT (relief);
4628 img->hmargin += abs (img->relief);
4629 img->vmargin += abs (img->relief);
4630 }
4631
4632 if (! img->background_valid)
4633 {
4634 bg = image_spec_value (img->spec, QCbackground, NULL);
4635 if (!NILP (bg))
4636 {
4637 img->background
4638 = x_alloc_image_color (f, img, bg,
4639 FRAME_BACKGROUND_PIXEL (f));
4640 img->background_valid = 1;
4641 }
4642 }
4643
4644 /* Do image transformations and compute masks, unless we
4645 don't have the image yet. */
4646 if (!EQ (*img->type->type, Qpostscript))
4647 postprocess_image (f, img);
4648 }
4649
4650 UNBLOCK_INPUT;
4651 }
4652
4653 /* We're using IMG, so set its timestamp to `now'. */
4654 EMACS_GET_TIME (now);
4655 img->timestamp = EMACS_SECS (now);
4656
4657 UNGCPRO;
4658
4659 /* Value is the image id. */
4660 return img->id;
4661}
4662
4663
4664/* Cache image IMG in the image cache of frame F. */
4665
4666static void
4667cache_image (f, img)
4668 struct frame *f;
4669 struct image *img;
4670{
4671 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
4672 int i;
4673
4674 /* Find a free slot in c->images. */
4675 for (i = 0; i < c->used; ++i)
4676 if (c->images[i] == NULL)
4677 break;
4678
4679 /* If no free slot found, maybe enlarge c->images. */
4680 if (i == c->used && c->used == c->size)
4681 {
4682 c->size *= 2;
4683 c->images = (struct image **) xrealloc (c->images,
4684 c->size * sizeof *c->images);
4685 }
4686
4687 /* Add IMG to c->images, and assign IMG an id. */
4688 c->images[i] = img;
4689 img->id = i;
4690 if (i == c->used)
4691 ++c->used;
4692
4693 /* Add IMG to the cache's hash table. */
4694 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
4695 img->next = c->buckets[i];
4696 if (img->next)
4697 img->next->prev = img;
4698 img->prev = NULL;
4699 c->buckets[i] = img;
4700}
4701
4702
4703/* Call FN on every image in the image cache of frame F. Used to mark
4704 Lisp Objects in the image cache. */
4705
4706void
4707forall_images_in_image_cache (f, fn)
4708 struct frame *f;
4709 void (*fn) P_ ((struct image *img));
4710{
4711 if (FRAME_LIVE_P (f) && FRAME_MAC_P (f))
4712 {
4713 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
4714 if (c)
4715 {
4716 int i;
4717 for (i = 0; i < c->used; ++i)
4718 if (c->images[i])
4719 fn (c->images[i]);
4720 }
4721 }
4722}
4723
4724
4725
4726/***********************************************************************
4727 Mac support code
4728 ***********************************************************************/
4729
4730static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
4731 XImagePtr *, Pixmap *));
4732static void x_destroy_x_image P_ ((XImagePtr));
4733static void x_put_x_image P_ ((struct frame *, XImagePtr, Pixmap, int, int));
4734
4735
4736x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
4737 struct frame *f;
4738 int width, height, depth;
4739 XImagePtr *ximg;
4740 Pixmap *pixmap;
4741{
4742 Display *display = FRAME_MAC_DISPLAY (f);
4743 Window window = FRAME_MAC_WINDOW (f);
4744
4745 xassert (interrupt_input_blocked);
4746
4747 /* Allocate a pixmap of the same size. */
4748 *pixmap = XCreatePixmap (display, window, width, height, depth);
4749 if (*pixmap == 0)
4750 {
4751 x_destroy_x_image (*ximg);
4752 *ximg = NULL;
4753 image_error ("Unable to create X pixmap", Qnil, Qnil);
4754 return 0;
4755 }
4756
4757 LockPixels (GetGWorldPixMap (*pixmap));
4758 *ximg = *pixmap;
4759 return 1;
4760}
4761
4762static void
4763x_destroy_x_image (ximg)
4764 XImagePtr ximg;
4765{
4766 xassert (interrupt_input_blocked);
4767 if (ximg)
4768 XDestroyImage (ximg);
4769}
4770
4771static void
4772x_put_x_image (f, ximg, pixmap, width, height)
4773 struct frame *f;
4774 XImagePtr ximg;
4775 Pixmap pixmap;
4776{
4777 xassert (ximg == pixmap);
4778}
4779
4780
4781
4782/***********************************************************************
4783 File Handling
4784 ***********************************************************************/
4785
4786static Lisp_Object x_find_image_file P_ ((Lisp_Object));
4787static char *slurp_file P_ ((char *, int *));
4788
4789
4790/* Find image file FILE. Look in data-directory, then
4791 x-bitmap-file-path. Value is the full name of the file found, or
4792 nil if not found. */
4793
4794static Lisp_Object
4795x_find_image_file (file)
4796 Lisp_Object file;
4797{
4798 Lisp_Object file_found, search_path;
4799 struct gcpro gcpro1, gcpro2;
4800 int fd;
4801
4802 file_found = Qnil;
4803 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
4804 GCPRO2 (file_found, search_path);
4805
4806 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
4807 fd = openp (search_path, file, Qnil, &file_found, Qnil);
4808
4809 if (fd == -1)
4810 file_found = Qnil;
4811 else
4812 close (fd);
4813
4814 UNGCPRO;
4815 return file_found;
4816}
4817
4818
4819/* Read FILE into memory. Value is a pointer to a buffer allocated
4820 with xmalloc holding FILE's contents. Value is null if an error
4821 occurred. *SIZE is set to the size of the file. */
4822
4823static char *
4824slurp_file (file, size)
4825 char *file;
4826 int *size;
4827{
4828 FILE *fp = NULL;
4829 char *buf = NULL;
4830 struct stat st;
4831
4832 if (stat (file, &st) == 0
4833 && (fp = fopen (file, "r")) != NULL
4834 && (buf = (char *) xmalloc (st.st_size),
4835 fread (buf, 1, st.st_size, fp) == st.st_size))
4836 {
4837 *size = st.st_size;
4838 fclose (fp);
4839 }
4840 else
4841 {
4842 if (fp)
4843 fclose (fp);
4844 if (buf)
4845 {
4846 xfree (buf);
4847 buf = NULL;
4848 }
4849 }
4850
4851 return buf;
4852}
4853
4854
4855
4856/***********************************************************************
4857 Image Load Functions
4858 ***********************************************************************/
4859
4860static int image_load_quicktime P_ ((struct frame *, struct image *img,
4861 OSType));
4862#ifdef MAC_OSX
4863static int image_load_quartz2d P_ ((struct frame *, struct image *img, int));
4864#endif
4865
4866
4867static OSErr
4868find_image_fsspec (specified_file, file, fss)
4869 Lisp_Object specified_file, *file;
4870 FSSpec *fss;
4871{
4872#if TARGET_API_MAC_CARBON
4873 FSRef fsr;
4874#else
4875 Str255 mac_pathname;
4876#endif
4877 OSErr err;
4878
4879 *file = x_find_image_file (specified_file);
4880 if (!STRINGP (*file))
4881 return fnfErr; /* file or directory not found;
4882 incomplete pathname */
4883 /* Try to open the image file. */
4884#if TARGET_API_MAC_CARBON
4885 err = FSPathMakeRef (SDATA (*file), &fsr, NULL);
4886 if (err == noErr)
4887 err = FSGetCatalogInfo (&fsr, kFSCatInfoNone, NULL, NULL, fss, NULL);
4888#else
4889 if (posix_to_mac_pathname (SDATA (*file), mac_pathname, MAXPATHLEN+1) == 0)
4890 return fnfErr;
4891 c2pstr (mac_pathname);
4892 err = FSMakeFSSpec (0, 0, mac_pathname, fss);
4893#endif
4894 return err;
4895}
4896
4897
4898static int
4899image_load_qt_1 (f, img, type, fss, dh)
4900 struct frame *f;
4901 struct image *img;
4902 OSType type;
4903 FSSpec *fss;
4904 Handle dh;
4905{
4906 OSErr err;
4907 GraphicsImportComponent gi;
4908 Rect rect;
4909 int width, height;
4910 short draw_all_pixels;
4911 Lisp_Object specified_bg;
4912 XColor color;
4913 XImagePtr ximg;
4914 RGBColor bg_color;
4915
4916 err = OpenADefaultComponent (GraphicsImporterComponentType,
4917 type, &gi);
4918 if (err != noErr)
4919 {
4920 image_error ("Cannot get importer component for `%s'", img->spec, Qnil);
4921 return 0;
4922 }
4923 if (dh == NULL)
4924 {
4925 /* read from file system spec */
4926 err = GraphicsImportSetDataFile (gi, fss);
4927 if (err != noErr)
4928 {
4929 image_error ("Cannot set fsspec to graphics importer for '%s'",
4930 img->spec, Qnil);
4931 goto error;
4932 }
4933 }
4934 else
4935 {
4936 /* read from data handle */
4937 err = GraphicsImportSetDataHandle (gi, dh);
4938 if (err != noErr)
4939 {
4940 image_error ("Cannot set data handle to graphics importer for `%s'",
4941 img->spec, Qnil);
4942 goto error;
4943 }
4944 }
4945 err = GraphicsImportGetNaturalBounds (gi, &rect);
4946 if (err != noErr)
4947 {
4948 image_error ("Error reading `%s'", img->spec, Qnil);
4949 goto error;
4950 }
4951 width = img->width = rect.right - rect.left;
4952 height = img->height = rect.bottom - rect.top;
4953 err = GraphicsImportDoesDrawAllPixels (gi, &draw_all_pixels);
4954#if 0
4955 /* Don't check the error code here. It may have an undocumented
4956 value -32766. */
4957 if (err != noErr)
4958 {
4959 image_error ("Error reading `%s'", img->spec, Qnil);
4960 goto error;
4961 }
4962#endif
4963 if (draw_all_pixels != graphicsImporterDrawsAllPixels)
4964 {
4965 specified_bg = image_spec_value (img->spec, QCbackground, NULL);
4966 if (!STRINGP (specified_bg) ||
4967 !mac_defined_color (f, SDATA (specified_bg), &color, 0))
4968 {
4969 color.pixel = FRAME_BACKGROUND_PIXEL (f);
4970 color.red = RED16_FROM_ULONG (color.pixel);
4971 color.green = GREEN16_FROM_ULONG (color.pixel);
4972 color.blue = BLUE16_FROM_ULONG (color.pixel);
4973 }
4974 }
4975
4976 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
4977 goto error;
4978 if (draw_all_pixels != graphicsImporterDrawsAllPixels)
4979 {
4980 SetGWorld (ximg, NULL);
4981 bg_color.red = color.red;
4982 bg_color.green = color.green;
4983 bg_color.blue = color.blue;
4984 RGBBackColor (&bg_color);
4985#if TARGET_API_MAC_CARBON
4986 GetPortBounds (ximg, &rect);
4987 EraseRect (&rect);
4988#else
4989 EraseRect (&(ximg->portRect));
4990#endif
4991 }
4992 GraphicsImportSetGWorld (gi, ximg, NULL);
4993 GraphicsImportDraw (gi);
4994 CloseComponent (gi);
4995
4996 /* Maybe fill in the background field while we have ximg handy. */
4997 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
4998 IMAGE_BACKGROUND (img, f, ximg);
4999
5000 /* Put the image into the pixmap. */
5001 x_put_x_image (f, ximg, img->pixmap, width, height);
5002 x_destroy_x_image (ximg);
5003 return 1;
5004
5005 error:
5006 CloseComponent (gi);
5007 return 0;
5008}
5009
5010
5011/* Load an image using the QuickTime Graphics Importer.
5012 Note: The alpha channel does not work for PNG images. */
5013static int
5014image_load_quicktime (f, img, type)
5015 struct frame *f;
5016 struct image *img;
5017 OSType type;
5018{
5019 Lisp_Object specified_file;
5020 Lisp_Object specified_data;
5021 OSErr err;
5022
5023 specified_file = image_spec_value (img->spec, QCfile, NULL);
5024 specified_data = image_spec_value (img->spec, QCdata, NULL);
5025
5026 if (NILP (specified_data))
5027 {
5028 /* Read from a file */
5029 Lisp_Object file;
5030 FSSpec fss;
5031
5032 err = find_image_fsspec (specified_file, &file, &fss);
5033 if (err != noErr)
5034 {
5035 if (err == fnfErr)
5036 image_error ("Cannot find image file `%s'", specified_file, Qnil);
5037 else
5038 image_error ("Cannot open `%s'", file, Qnil);
5039 return 0;
5040 }
5041 return image_load_qt_1 (f, img, type, &fss, NULL);
5042 }
5043 else
5044 {
5045 /* Memory source! */
5046 int success_p;
5047 Handle dh;
5048
5049 err = PtrToHand (SDATA (specified_data), &dh, SBYTES (specified_data));
5050 if (err != noErr)
5051 {
5052 image_error ("Cannot allocate data handle for `%s'",
5053 img->spec, Qnil);
5054 return 0;
5055 }
5056 success_p = image_load_qt_1 (f, img, type, NULL, dh);
5057 DisposeHandle (dh);
5058 return success_p;
5059 }
5060}
5061
5062
5063#ifdef MAC_OSX
5064/* Load a PNG/JPEG image using Quartz 2D decoding routines.
5065 CGImageCreateWithPNGDataProvider is provided after Mac OS X 10.2.
5066 So don't use this function directly but determine at runtime
5067 whether it exists. */
5068typedef CGImageRef (*CGImageCreateWithPNGDataProviderProcType)
5069 (CGDataProviderRef, const float [], bool, CGColorRenderingIntent);
5070static CGImageCreateWithPNGDataProviderProcType MyCGImageCreateWithPNGDataProvider;
5071
5072
5073static void
5074init_image_func_pointer ()
5075{
5076 if (NSIsSymbolNameDefined ("_CGImageCreateWithPNGDataProvider"))
5077 {
5078 MyCGImageCreateWithPNGDataProvider
5079 = (CGImageCreateWithPNGDataProviderProcType)
5080 NSAddressOfSymbol (NSLookupAndBindSymbol
5081 ("_CGImageCreateWithPNGDataProvider"));
5082 }
5083 else
5084 MyCGImageCreateWithPNGDataProvider = NULL;
5085}
5086
5087
5088static int
5089image_load_quartz2d (f, img, png_p)
5090 struct frame *f;
5091 struct image *img;
5092 int png_p;
5093{
5094 Lisp_Object file, specified_file;
5095 Lisp_Object specified_data, specified_bg;
5096 struct gcpro gcpro1;
5097 CGDataProviderRef source;
5098 CGImageRef image;
5099 int width, height;
5100 XColor color;
5101 XImagePtr ximg = NULL;
5102 CGContextRef context;
5103 CGRect rectangle;
5104
5105 /* Open the file. */
5106 specified_file = image_spec_value (img->spec, QCfile, NULL);
5107 specified_data = image_spec_value (img->spec, QCdata, NULL);
5108
5109 file = Qnil;
5110 GCPRO1 (file);
5111
5112 if (NILP (specified_data))
5113 {
5114 CFStringRef path;
5115 CFURLRef url;
5116
5117 file = x_find_image_file (specified_file);
5118 if (!STRINGP (file))
5119 {
5120 image_error ("Cannot find image file `%s'", specified_file, Qnil);
5121 UNGCPRO;
5122 return 0;
5123 }
5124 path = CFStringCreateWithCString (NULL, SDATA (file),
5125 kCFStringEncodingUTF8);
5126 url = CFURLCreateWithFileSystemPath (NULL, path,
5127 kCFURLPOSIXPathStyle, 0);
5128 CFRelease (path);
5129 source = CGDataProviderCreateWithURL (url);
5130 CFRelease (url);
5131 }
5132 else
5133 source = CGDataProviderCreateWithData (NULL, SDATA (specified_data),
5134 SBYTES (specified_data), NULL);
5135
5136 if (png_p)
5137 image = (*MyCGImageCreateWithPNGDataProvider) (source, NULL, FALSE,
5138 kCGRenderingIntentDefault);
5139 else
5140 image = CGImageCreateWithJPEGDataProvider (source, NULL, FALSE,
5141 kCGRenderingIntentDefault);
5142
5143 CGDataProviderRelease (source);
5144 if (image == NULL)
5145 {
5146 UNGCPRO;
5147 image_error ("Error reading image `%s'", img->spec, Qnil);
5148 return 0;
5149 }
5150
5151 if (png_p)
5152 {
5153 specified_bg = image_spec_value (img->spec, QCbackground, NULL);
5154 if (!STRINGP (specified_bg) ||
5155 !mac_defined_color (f, SDATA (specified_bg), &color, 0))
5156 {
5157 color.pixel = FRAME_BACKGROUND_PIXEL (f);
5158 color.red = RED16_FROM_ULONG (color.pixel);
5159 color.green = GREEN16_FROM_ULONG (color.pixel);
5160 color.blue = BLUE16_FROM_ULONG (color.pixel);
5161 }
5162 }
5163 width = img->width = CGImageGetWidth (image);
5164 height = img->height = CGImageGetHeight (image);
5165 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
5166 {
5167 CGImageRelease (image);
5168 UNGCPRO;
5169 return 0;
5170 }
5171 rectangle = CGRectMake (0, 0, width, height);
5172 QDBeginCGContext (ximg, &context);
5173 if (png_p)
5174 {
5175 CGContextSetRGBFillColor (context, color.red / 65535.0,
5176 color.green / 65535.0,
5177 color.blue / 65535.0, 1.0);
5178 CGContextFillRect (context, rectangle);
5179 }
5180 CGContextDrawImage (context, rectangle, image);
5181 QDEndCGContext (ximg, &context);
5182 CGImageRelease (image);
5183
5184 /* Maybe fill in the background field while we have ximg handy. */
5185 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
5186 IMAGE_BACKGROUND (img, f, ximg);
5187
5188 /* Put the image into the pixmap. */
5189 x_put_x_image (f, ximg, img->pixmap, width, height);
5190 x_destroy_x_image (ximg);
5191 UNGCPRO;
5192 return 1;
5193}
5194#endif
5195
5196
5197
5198/***********************************************************************
5199 XBM images
5200 ***********************************************************************/
5201
5202static int xbm_scan P_ ((char **, char *, char *, int *));
5203static int xbm_load P_ ((struct frame *f, struct image *img));
5204static int xbm_load_image P_ ((struct frame *f, struct image *img,
5205 char *, char *));
5206static int xbm_image_p P_ ((Lisp_Object object));
5207static int xbm_read_bitmap_data P_ ((char *, char *, int *, int *,
5208 unsigned char **));
5209static int xbm_file_p P_ ((Lisp_Object));
5210
5211
5212/* Indices of image specification fields in xbm_format, below. */
5213
5214enum xbm_keyword_index
5215{
5216 XBM_TYPE,
5217 XBM_FILE,
5218 XBM_WIDTH,
5219 XBM_HEIGHT,
5220 XBM_DATA,
5221 XBM_FOREGROUND,
5222 XBM_BACKGROUND,
5223 XBM_ASCENT,
5224 XBM_MARGIN,
5225 XBM_RELIEF,
5226 XBM_ALGORITHM,
5227 XBM_HEURISTIC_MASK,
5228 XBM_MASK,
5229 XBM_LAST
5230};
5231
5232/* Vector of image_keyword structures describing the format
5233 of valid XBM image specifications. */
5234
5235static struct image_keyword xbm_format[XBM_LAST] =
5236{
5237 {":type", IMAGE_SYMBOL_VALUE, 1},
5238 {":file", IMAGE_STRING_VALUE, 0},
5239 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
5240 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
5241 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5242 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
5243 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
5244 {":ascent", IMAGE_ASCENT_VALUE, 0},
5245 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
5246 {":relief", IMAGE_INTEGER_VALUE, 0},
5247 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5248 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5249 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
5250};
5251
5252/* Structure describing the image type XBM. */
5253
5254static struct image_type xbm_type =
5255{
5256 &Qxbm,
5257 xbm_image_p,
5258 xbm_load,
5259 x_clear_image,
5260 NULL
5261};
5262
5263/* Tokens returned from xbm_scan. */
5264
5265enum xbm_token
5266{
5267 XBM_TK_IDENT = 256,
5268 XBM_TK_NUMBER
5269};
5270
5271
5272/* Return non-zero if OBJECT is a valid XBM-type image specification.
5273 A valid specification is a list starting with the symbol `image'
5274 The rest of the list is a property list which must contain an
5275 entry `:type xbm..
5276
5277 If the specification specifies a file to load, it must contain
5278 an entry `:file FILENAME' where FILENAME is a string.
5279
5280 If the specification is for a bitmap loaded from memory it must
5281 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
5282 WIDTH and HEIGHT are integers > 0. DATA may be:
5283
5284 1. a string large enough to hold the bitmap data, i.e. it must
5285 have a size >= (WIDTH + 7) / 8 * HEIGHT
5286
5287 2. a bool-vector of size >= WIDTH * HEIGHT
5288
5289 3. a vector of strings or bool-vectors, one for each line of the
5290 bitmap.
5291
5292 4. A string containing an in-memory XBM file. WIDTH and HEIGHT
5293 may not be specified in this case because they are defined in the
5294 XBM file.
5295
5296 Both the file and data forms may contain the additional entries
5297 `:background COLOR' and `:foreground COLOR'. If not present,
5298 foreground and background of the frame on which the image is
5299 displayed is used. */
5300
5301static int
5302xbm_image_p (object)
5303 Lisp_Object object;
5304{
5305 struct image_keyword kw[XBM_LAST];
5306
5307 bcopy (xbm_format, kw, sizeof kw);
5308 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
5309 return 0;
5310
5311 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
5312
5313 if (kw[XBM_FILE].count)
5314 {
5315 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
5316 return 0;
5317 }
5318 else if (kw[XBM_DATA].count && xbm_file_p (kw[XBM_DATA].value))
5319 {
5320 /* In-memory XBM file. */
5321 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_FILE].count)
5322 return 0;
5323 }
5324 else
5325 {
5326 Lisp_Object data;
5327 int width, height;
5328
5329 /* Entries for `:width', `:height' and `:data' must be present. */
5330 if (!kw[XBM_WIDTH].count
5331 || !kw[XBM_HEIGHT].count
5332 || !kw[XBM_DATA].count)
5333 return 0;
5334
5335 data = kw[XBM_DATA].value;
5336 width = XFASTINT (kw[XBM_WIDTH].value);
5337 height = XFASTINT (kw[XBM_HEIGHT].value);
5338
5339 /* Check type of data, and width and height against contents of
5340 data. */
5341 if (VECTORP (data))
5342 {
5343 int i;
5344
5345 /* Number of elements of the vector must be >= height. */
5346 if (XVECTOR (data)->size < height)
5347 return 0;
5348
5349 /* Each string or bool-vector in data must be large enough
5350 for one line of the image. */
5351 for (i = 0; i < height; ++i)
5352 {
5353 Lisp_Object elt = XVECTOR (data)->contents[i];
5354
5355 if (STRINGP (elt))
5356 {
5357 if (SCHARS (elt)
5358 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
5359 return 0;
5360 }
5361 else if (BOOL_VECTOR_P (elt))
5362 {
5363 if (XBOOL_VECTOR (elt)->size < width)
5364 return 0;
5365 }
5366 else
5367 return 0;
5368 }
5369 }
5370 else if (STRINGP (data))
5371 {
5372 if (SCHARS (data)
5373 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
5374 return 0;
5375 }
5376 else if (BOOL_VECTOR_P (data))
5377 {
5378 if (XBOOL_VECTOR (data)->size < width * height)
5379 return 0;
5380 }
5381 else
5382 return 0;
5383 }
5384
5385 return 1;
5386}
5387
5388
5389/* Scan a bitmap file. FP is the stream to read from. Value is
5390 either an enumerator from enum xbm_token, or a character for a
5391 single-character token, or 0 at end of file. If scanning an
5392 identifier, store the lexeme of the identifier in SVAL. If
5393 scanning a number, store its value in *IVAL. */
5394
5395static int
5396xbm_scan (s, end, sval, ival)
5397 char **s, *end;
5398 char *sval;
5399 int *ival;
5400{
5401 int c;
5402
5403 loop:
5404
5405 /* Skip white space. */
5406 while (*s < end && (c = *(*s)++, isspace (c)))
5407 ;
5408
5409 if (*s >= end)
5410 c = 0;
5411 else if (isdigit (c))
5412 {
5413 int value = 0, digit;
5414
5415 if (c == '0' && *s < end)
5416 {
5417 c = *(*s)++;
5418 if (c == 'x' || c == 'X')
5419 {
5420 while (*s < end)
5421 {
5422 c = *(*s)++;
5423 if (isdigit (c))
5424 digit = c - '0';
5425 else if (c >= 'a' && c <= 'f')
5426 digit = c - 'a' + 10;
5427 else if (c >= 'A' && c <= 'F')
5428 digit = c - 'A' + 10;
5429 else
5430 break;
5431 value = 16 * value + digit;
5432 }
5433 }
5434 else if (isdigit (c))
5435 {
5436 value = c - '0';
5437 while (*s < end
5438 && (c = *(*s)++, isdigit (c)))
5439 value = 8 * value + c - '0';
5440 }
5441 }
5442 else
5443 {
5444 value = c - '0';
5445 while (*s < end
5446 && (c = *(*s)++, isdigit (c)))
5447 value = 10 * value + c - '0';
5448 }
5449
5450 if (*s < end)
5451 *s = *s - 1;
5452 *ival = value;
5453 c = XBM_TK_NUMBER;
5454 }
5455 else if (isalpha (c) || c == '_')
5456 {
5457 *sval++ = c;
5458 while (*s < end
5459 && (c = *(*s)++, (isalnum (c) || c == '_')))
5460 *sval++ = c;
5461 *sval = 0;
5462 if (*s < end)
5463 *s = *s - 1;
5464 c = XBM_TK_IDENT;
5465 }
5466 else if (c == '/' && **s == '*')
5467 {
5468 /* C-style comment. */
5469 ++*s;
5470 while (**s && (**s != '*' || *(*s + 1) != '/'))
5471 ++*s;
5472 if (**s)
5473 {
5474 *s += 2;
5475 goto loop;
5476 }
5477 }
5478
5479 return c;
5480}
5481
5482
5483/* Replacement for XReadBitmapFileData which isn't available under old
5484 X versions. CONTENTS is a pointer to a buffer to parse; END is the
5485 buffer's end. Set *WIDTH and *HEIGHT to the width and height of
5486 the image. Return in *DATA the bitmap data allocated with xmalloc.
5487 Value is non-zero if successful. DATA null means just test if
5488 CONTENTS looks like an in-memory XBM file. */
5489
5490static int
5491xbm_read_bitmap_data (contents, end, width, height, data)
5492 char *contents, *end;
5493 int *width, *height;
5494 unsigned char **data;
5495{
5496 char *s = contents;
5497 char buffer[BUFSIZ];
5498 int padding_p = 0;
5499 int v10 = 0;
5500 int bytes_per_line, i, nbytes;
5501 unsigned char *p;
5502 int value;
5503 int LA1;
5504
5505#define match() \
5506 LA1 = xbm_scan (&s, end, buffer, &value)
5507
5508#define expect(TOKEN) \
5509 if (LA1 != (TOKEN)) \
5510 goto failure; \
5511 else \
5512 match ()
5513
5514#define expect_ident(IDENT) \
5515 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
5516 match (); \
5517 else \
5518 goto failure
5519
5520 *width = *height = -1;
5521 if (data)
5522 *data = NULL;
5523 LA1 = xbm_scan (&s, end, buffer, &value);
5524
5525 /* Parse defines for width, height and hot-spots. */
5526 while (LA1 == '#')
5527 {
5528 match ();
5529 expect_ident ("define");
5530 expect (XBM_TK_IDENT);
5531
5532 if (LA1 == XBM_TK_NUMBER);
5533 {
5534 char *p = strrchr (buffer, '_');
5535 p = p ? p + 1 : buffer;
5536 if (strcmp (p, "width") == 0)
5537 *width = value;
5538 else if (strcmp (p, "height") == 0)
5539 *height = value;
5540 }
5541 expect (XBM_TK_NUMBER);
5542 }
5543
5544 if (*width < 0 || *height < 0)
5545 goto failure;
5546 else if (data == NULL)
5547 goto success;
5548
5549 /* Parse bits. Must start with `static'. */
5550 expect_ident ("static");
5551 if (LA1 == XBM_TK_IDENT)
5552 {
5553 if (strcmp (buffer, "unsigned") == 0)
5554 {
5555 match ();
5556 expect_ident ("char");
5557 }
5558 else if (strcmp (buffer, "short") == 0)
5559 {
5560 match ();
5561 v10 = 1;
5562 if (*width % 16 && *width % 16 < 9)
5563 padding_p = 1;
5564 }
5565 else if (strcmp (buffer, "char") == 0)
5566 match ();
5567 else
5568 goto failure;
5569 }
5570 else
5571 goto failure;
5572
5573 expect (XBM_TK_IDENT);
5574 expect ('[');
5575 expect (']');
5576 expect ('=');
5577 expect ('{');
5578
5579 bytes_per_line = (*width + 7) / 8 + padding_p;
5580 nbytes = bytes_per_line * *height;
5581 p = *data = (char *) xmalloc (nbytes);
5582
5583 if (v10)
5584 {
5585 for (i = 0; i < nbytes; i += 2)
5586 {
5587 int val = value;
5588 expect (XBM_TK_NUMBER);
5589
5590 *p++ = val;
5591 if (!padding_p || ((i + 2) % bytes_per_line))
5592 *p++ = value >> 8;
5593
5594 if (LA1 == ',' || LA1 == '}')
5595 match ();
5596 else
5597 goto failure;
5598 }
5599 }
5600 else
5601 {
5602 for (i = 0; i < nbytes; ++i)
5603 {
5604 int val = value;
5605 expect (XBM_TK_NUMBER);
5606
5607 *p++ = val;
5608
5609 if (LA1 == ',' || LA1 == '}')
5610 match ();
5611 else
5612 goto failure;
5613 }
5614 }
5615
5616 success:
5617 return 1;
5618
5619 failure:
5620
5621 if (data && *data)
5622 {
5623 xfree (*data);
5624 *data = NULL;
5625 }
5626 return 0;
5627
5628#undef match
5629#undef expect
5630#undef expect_ident
5631}
5632
5633
5634/* Load XBM image IMG which will be displayed on frame F from buffer
5635 CONTENTS. END is the end of the buffer. Value is non-zero if
5636 successful. */
5637
5638static int
5639xbm_load_image (f, img, contents, end)
5640 struct frame *f;
5641 struct image *img;
5642 char *contents, *end;
5643{
5644 int rc;
5645 unsigned char *data;
5646 int success_p = 0;
5647
5648 rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data);
5649 if (rc)
5650 {
5651 int depth = one_mac_display_info.n_planes;
5652 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
5653 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
5654 Lisp_Object value;
5655
5656 xassert (img->width > 0 && img->height > 0);
5657
5658 /* Get foreground and background colors, maybe allocate colors. */
5659 value = image_spec_value (img->spec, QCforeground, NULL);
5660 if (!NILP (value))
5661 foreground = x_alloc_image_color (f, img, value, foreground);
5662 value = image_spec_value (img->spec, QCbackground, NULL);
5663 if (!NILP (value))
5664 {
5665 background = x_alloc_image_color (f, img, value, background);
5666 img->background = background;
5667 img->background_valid = 1;
5668 }
5669
5670 img->pixmap
5671 = XCreatePixmapFromBitmapData (FRAME_MAC_DISPLAY (f),
5672 FRAME_MAC_WINDOW (f),
5673 data,
5674 img->width, img->height,
5675 foreground, background,
5676 depth);
5677 xfree (data);
5678
5679 if (img->pixmap == 0)
5680 {
5681 x_clear_image (f, img);
5682 image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil);
5683 }
5684 else
5685 success_p = 1;
5686 }
5687 else
5688 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
5689
5690 return success_p;
5691}
5692
5693
5694/* Value is non-zero if DATA looks like an in-memory XBM file. */
5695
5696static int
5697xbm_file_p (data)
5698 Lisp_Object data;
5699{
5700 int w, h;
5701 return (STRINGP (data)
5702 && xbm_read_bitmap_data (SDATA (data),
5703 (SDATA (data)
5704 + SBYTES (data)),
5705 &w, &h, NULL));
5706}
5707
5708
5709/* Fill image IMG which is used on frame F with pixmap data. Value is
5710 non-zero if successful. */
5711
5712static int
5713xbm_load (f, img)
5714 struct frame *f;
5715 struct image *img;
5716{
5717 int success_p = 0;
5718 Lisp_Object file_name;
5719
5720 xassert (xbm_image_p (img->spec));
5721
5722 /* If IMG->spec specifies a file name, create a non-file spec from it. */
5723 file_name = image_spec_value (img->spec, QCfile, NULL);
5724 if (STRINGP (file_name))
5725 {
5726 Lisp_Object file;
5727 char *contents;
5728 int size;
5729 struct gcpro gcpro1;
5730
5731 file = x_find_image_file (file_name);
5732 GCPRO1 (file);
5733 if (!STRINGP (file))
5734 {
5735 image_error ("Cannot find image file `%s'", file_name, Qnil);
5736 UNGCPRO;
5737 return 0;
5738 }
5739
5740 contents = slurp_file (SDATA (file), &size);
5741 if (contents == NULL)
5742 {
5743 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
5744 UNGCPRO;
5745 return 0;
5746 }
5747
5748 success_p = xbm_load_image (f, img, contents, contents + size);
5749 UNGCPRO;
5750 }
5751 else
5752 {
5753 struct image_keyword fmt[XBM_LAST];
5754 Lisp_Object data;
5755 int depth;
5756 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
5757 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
5758 char *bits;
5759 int parsed_p;
5760 int in_memory_file_p = 0;
5761
5762 /* See if data looks like an in-memory XBM file. */
5763 data = image_spec_value (img->spec, QCdata, NULL);
5764 in_memory_file_p = xbm_file_p (data);
5765
5766 /* Parse the image specification. */
5767 bcopy (xbm_format, fmt, sizeof fmt);
5768 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
5769 xassert (parsed_p);
5770
5771 /* Get specified width, and height. */
5772 if (!in_memory_file_p)
5773 {
5774 img->width = XFASTINT (fmt[XBM_WIDTH].value);
5775 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
5776 xassert (img->width > 0 && img->height > 0);
5777 }
5778
5779 /* Get foreground and background colors, maybe allocate colors. */
5780 if (fmt[XBM_FOREGROUND].count
5781 && STRINGP (fmt[XBM_FOREGROUND].value))
5782 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
5783 foreground);
5784 if (fmt[XBM_BACKGROUND].count
5785 && STRINGP (fmt[XBM_BACKGROUND].value))
5786 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
5787 background);
5788
5789 if (in_memory_file_p)
5790 success_p = xbm_load_image (f, img, SDATA (data),
5791 (SDATA (data)
5792 + SBYTES (data)));
5793 else
5794 {
5795 if (VECTORP (data))
5796 {
5797 int i;
5798 char *p;
5799 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
5800
5801 p = bits = (char *) alloca (nbytes * img->height);
5802 for (i = 0; i < img->height; ++i, p += nbytes)
5803 {
5804 Lisp_Object line = XVECTOR (data)->contents[i];
5805 if (STRINGP (line))
5806 bcopy (SDATA (line), p, nbytes);
5807 else
5808 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
5809 }
5810 }
5811 else if (STRINGP (data))
5812 bits = SDATA (data);
5813 else
5814 bits = XBOOL_VECTOR (data)->data;
5815
5816 /* Create the pixmap. */
5817 depth = one_mac_display_info.n_planes;
5818 img->pixmap
5819 = XCreatePixmapFromBitmapData (FRAME_MAC_DISPLAY (f),
5820 FRAME_MAC_WINDOW (f),
5821 bits,
5822 img->width, img->height,
5823 foreground, background,
5824 depth);
5825 if (img->pixmap)
5826 success_p = 1;
5827 else
5828 {
5829 image_error ("Unable to create pixmap for XBM image `%s'",
5830 img->spec, Qnil);
5831 x_clear_image (f, img);
5832 }
5833 }
5834 }
5835
5836 return success_p;
5837}
5838
5839
5840
5841/***********************************************************************
5842 XPM images
5843 ***********************************************************************/
5844
5845#if HAVE_XPM
5846
5847static int xpm_image_p P_ ((Lisp_Object object));
5848static int xpm_load P_ ((struct frame *f, struct image *img));
5849static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
5850
5851#include "X11/xpm.h"
5852
5853/* The symbol `xpm' identifying XPM-format images. */
5854
5855Lisp_Object Qxpm;
5856
5857/* Indices of image specification fields in xpm_format, below. */
5858
5859enum xpm_keyword_index
5860{
5861 XPM_TYPE,
5862 XPM_FILE,
5863 XPM_DATA,
5864 XPM_ASCENT,
5865 XPM_MARGIN,
5866 XPM_RELIEF,
5867 XPM_ALGORITHM,
5868 XPM_HEURISTIC_MASK,
5869 XPM_MASK,
5870 XPM_COLOR_SYMBOLS,
5871 XPM_BACKGROUND,
5872 XPM_LAST
5873};
5874
5875/* Vector of image_keyword structures describing the format
5876 of valid XPM image specifications. */
5877
5878static struct image_keyword xpm_format[XPM_LAST] =
5879{
5880 {":type", IMAGE_SYMBOL_VALUE, 1},
5881 {":file", IMAGE_STRING_VALUE, 0},
5882 {":data", IMAGE_STRING_VALUE, 0},
5883 {":ascent", IMAGE_ASCENT_VALUE, 0},
5884 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
5885 {":relief", IMAGE_INTEGER_VALUE, 0},
5886 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5887 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5888 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5889 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5890 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
5891};
5892
5893/* Structure describing the image type XBM. */
5894
5895static struct image_type xpm_type =
5896{
5897 &Qxpm,
5898 xpm_image_p,
5899 xpm_load,
5900 x_clear_image,
5901 NULL
5902};
5903
5904
5905/* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
5906 for XPM images. Such a list must consist of conses whose car and
5907 cdr are strings. */
5908
5909static int
5910xpm_valid_color_symbols_p (color_symbols)
5911 Lisp_Object color_symbols;
5912{
5913 while (CONSP (color_symbols))
5914 {
5915 Lisp_Object sym = XCAR (color_symbols);
5916 if (!CONSP (sym)
5917 || !STRINGP (XCAR (sym))
5918 || !STRINGP (XCDR (sym)))
5919 break;
5920 color_symbols = XCDR (color_symbols);
5921 }
5922
5923 return NILP (color_symbols);
5924}
5925
5926
5927/* Value is non-zero if OBJECT is a valid XPM image specification. */
5928
5929static int
5930xpm_image_p (object)
5931 Lisp_Object object;
5932{
5933 struct image_keyword fmt[XPM_LAST];
5934 bcopy (xpm_format, fmt, sizeof fmt);
5935 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
5936 /* Either `:file' or `:data' must be present. */
5937 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
5938 /* Either no `:color-symbols' or it's a list of conses
5939 whose car and cdr are strings. */
5940 && (fmt[XPM_COLOR_SYMBOLS].count == 0
5941 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value)));
5942}
5943
5944
5945/* Load image IMG which will be displayed on frame F. Value is
5946 non-zero if successful. */
5947
5948static int
5949xpm_load (f, img)
5950 struct frame *f;
5951 struct image *img;
5952{
5953 int rc;
5954 XpmAttributes attrs;
5955 Lisp_Object specified_file, color_symbols;
5956
5957 /* Configure the XPM lib. Use the visual of frame F. Allocate
5958 close colors. Return colors allocated. */
5959 bzero (&attrs, sizeof attrs);
5960 attrs.visual = FRAME_X_VISUAL (f);
5961 attrs.colormap = FRAME_X_COLORMAP (f);
5962 attrs.valuemask |= XpmVisual;
5963 attrs.valuemask |= XpmColormap;
5964 attrs.valuemask |= XpmReturnAllocPixels;
5965#ifdef XpmAllocCloseColors
5966 attrs.alloc_close_colors = 1;
5967 attrs.valuemask |= XpmAllocCloseColors;
5968#else /* not XpmAllocCloseColors */
5969 attrs.closeness = 600;
5970 attrs.valuemask |= XpmCloseness;
5971#endif /* not XpmAllocCloseColors */
5972
5973 /* If image specification contains symbolic color definitions, add
5974 these to `attrs'. */
5975 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
5976 if (CONSP (color_symbols))
5977 {
5978 Lisp_Object tail;
5979 XpmColorSymbol *xpm_syms;
5980 int i, size;
5981
5982 attrs.valuemask |= XpmColorSymbols;
5983
5984 /* Count number of symbols. */
5985 attrs.numsymbols = 0;
5986 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
5987 ++attrs.numsymbols;
5988
5989 /* Allocate an XpmColorSymbol array. */
5990 size = attrs.numsymbols * sizeof *xpm_syms;
5991 xpm_syms = (XpmColorSymbol *) alloca (size);
5992 bzero (xpm_syms, size);
5993 attrs.colorsymbols = xpm_syms;
5994
5995 /* Fill the color symbol array. */
5996 for (tail = color_symbols, i = 0;
5997 CONSP (tail);
5998 ++i, tail = XCDR (tail))
5999 {
6000 Lisp_Object name = XCAR (XCAR (tail));
6001 Lisp_Object color = XCDR (XCAR (tail));
6002 xpm_syms[i].name = (char *) alloca (SCHARS (name) + 1);
6003 strcpy (xpm_syms[i].name, SDATA (name));
6004 xpm_syms[i].value = (char *) alloca (SCHARS (color) + 1);
6005 strcpy (xpm_syms[i].value, SDATA (color));
6006 }
6007 }
6008
6009 /* Create a pixmap for the image, either from a file, or from a
6010 string buffer containing data in the same format as an XPM file. */
6011
6012 specified_file = image_spec_value (img->spec, QCfile, NULL);
6013 if (STRINGP (specified_file))
6014 {
6015 Lisp_Object file = x_find_image_file (specified_file);
6016 if (!STRINGP (file))
6017 {
6018 image_error ("Cannot find image file `%s'", specified_file, Qnil);
6019 return 0;
6020 }
6021
6022 rc = XpmReadFileToPixmap (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
6023 SDATA (file), &img->pixmap, &img->mask,
6024 &attrs);
6025 }
6026 else
6027 {
6028 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
6029 rc = XpmCreatePixmapFromBuffer (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
6030 SDATA (buffer),
6031 &img->pixmap, &img->mask,
6032 &attrs);
6033 }
6034
6035 if (rc == XpmSuccess)
6036 {
6037 int i;
6038
6039 img->ncolors = attrs.nalloc_pixels;
6040 img->colors = (unsigned long *) xmalloc (img->ncolors
6041 * sizeof *img->colors);
6042 for (i = 0; i < attrs.nalloc_pixels; ++i)
6043 img->colors[i] = attrs.alloc_pixels[i];
6044
6045 img->width = attrs.width;
6046 img->height = attrs.height;
6047 xassert (img->width > 0 && img->height > 0);
6048
6049 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
6050 XpmFreeAttributes (&attrs);
6051 }
6052 else
6053 {
6054 switch (rc)
6055 {
6056 case XpmOpenFailed:
6057 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
6058 break;
6059
6060 case XpmFileInvalid:
6061 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
6062 break;
6063
6064 case XpmNoMemory:
6065 image_error ("Out of memory (%s)", img->spec, Qnil);
6066 break;
6067
6068 case XpmColorFailed:
6069 image_error ("Color allocation error (%s)", img->spec, Qnil);
6070 break;
6071
6072 default:
6073 image_error ("Unknown error (%s)", img->spec, Qnil);
6074 break;
6075 }
6076 }
6077
6078 return rc == XpmSuccess;
6079}
6080
6081#endif /* HAVE_XPM != 0 */
6082
6083
6084#if 0 /* MAC_TODO : Color tables on Mac. */
6085/***********************************************************************
6086 Color table
6087 ***********************************************************************/
6088
6089/* An entry in the color table mapping an RGB color to a pixel color. */
6090
6091struct ct_color
6092{
6093 int r, g, b;
6094 unsigned long pixel;
6095
6096 /* Next in color table collision list. */
6097 struct ct_color *next;
6098};
6099
6100/* The bucket vector size to use. Must be prime. */
6101
6102#define CT_SIZE 101
6103
6104/* Value is a hash of the RGB color given by R, G, and B. */
6105
6106#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
6107
6108/* The color hash table. */
6109
6110struct ct_color **ct_table;
6111
6112/* Number of entries in the color table. */
6113
6114int ct_colors_allocated;
6115
6116/* Initialize the color table. */
6117
6118static void
6119init_color_table ()
6120{
6121 int size = CT_SIZE * sizeof (*ct_table);
6122 ct_table = (struct ct_color **) xmalloc (size);
6123 bzero (ct_table, size);
6124 ct_colors_allocated = 0;
6125}
6126
6127
6128/* Free memory associated with the color table. */
6129
6130static void
6131free_color_table ()
6132{
6133 int i;
6134 struct ct_color *p, *next;
6135
6136 for (i = 0; i < CT_SIZE; ++i)
6137 for (p = ct_table[i]; p; p = next)
6138 {
6139 next = p->next;
6140 xfree (p);
6141 }
6142
6143 xfree (ct_table);
6144 ct_table = NULL;
6145}
6146
6147
6148/* Value is a pixel color for RGB color R, G, B on frame F. If an
6149 entry for that color already is in the color table, return the
6150 pixel color of that entry. Otherwise, allocate a new color for R,
6151 G, B, and make an entry in the color table. */
6152
6153static unsigned long
6154lookup_rgb_color (f, r, g, b)
6155 struct frame *f;
6156 int r, g, b;
6157{
6158 unsigned hash = CT_HASH_RGB (r, g, b);
6159 int i = hash % CT_SIZE;
6160 struct ct_color *p;
6161
6162 for (p = ct_table[i]; p; p = p->next)
6163 if (p->r == r && p->g == g && p->b == b)
6164 break;
6165
6166 if (p == NULL)
6167 {
6168 COLORREF color;
6169 Colormap cmap;
6170 int rc;
6171
6172 color = RGB_TO_ULONG (r, g, b);
6173
6174 ++ct_colors_allocated;
6175
6176 p = (struct ct_color *) xmalloc (sizeof *p);
6177 p->r = r;
6178 p->g = g;
6179 p->b = b;
6180 p->pixel = color;
6181 p->next = ct_table[i];
6182 ct_table[i] = p;
6183 }
6184
6185 return p->pixel;
6186}
6187
6188
6189/* Look up pixel color PIXEL which is used on frame F in the color
6190 table. If not already present, allocate it. Value is PIXEL. */
6191
6192static unsigned long
6193lookup_pixel_color (f, pixel)
6194 struct frame *f;
6195 unsigned long pixel;
6196{
6197 int i = pixel % CT_SIZE;
6198 struct ct_color *p;
6199
6200 for (p = ct_table[i]; p; p = p->next)
6201 if (p->pixel == pixel)
6202 break;
6203
6204 if (p == NULL)
6205 {
6206 XColor color;
6207 Colormap cmap;
6208 int rc;
6209
6210 BLOCK_INPUT;
6211
6212 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
6213 color.pixel = pixel;
6214 XQueryColor (NULL, cmap, &color);
6215 rc = x_alloc_nearest_color (f, cmap, &color);
6216 UNBLOCK_INPUT;
6217
6218 if (rc)
6219 {
6220 ++ct_colors_allocated;
6221
6222 p = (struct ct_color *) xmalloc (sizeof *p);
6223 p->r = color.red;
6224 p->g = color.green;
6225 p->b = color.blue;
6226 p->pixel = pixel;
6227 p->next = ct_table[i];
6228 ct_table[i] = p;
6229 }
6230 else
6231 return FRAME_FOREGROUND_PIXEL (f);
6232 }
6233 return p->pixel;
6234}
6235
6236
6237/* Value is a vector of all pixel colors contained in the color table,
6238 allocated via xmalloc. Set *N to the number of colors. */
6239
6240static unsigned long *
6241colors_in_color_table (n)
6242 int *n;
6243{
6244 int i, j;
6245 struct ct_color *p;
6246 unsigned long *colors;
6247
6248 if (ct_colors_allocated == 0)
6249 {
6250 *n = 0;
6251 colors = NULL;
6252 }
6253 else
6254 {
6255 colors = (unsigned long *) xmalloc (ct_colors_allocated
6256 * sizeof *colors);
6257 *n = ct_colors_allocated;
6258
6259 for (i = j = 0; i < CT_SIZE; ++i)
6260 for (p = ct_table[i]; p; p = p->next)
6261 colors[j++] = p->pixel;
6262 }
6263
6264 return colors;
6265}
6266
6267#else
6268static unsigned long
6269lookup_rgb_color (f, r, g, b)
6270 struct frame *f;
6271 int r, g, b;
6272{
6273 unsigned long pixel = RGB_TO_ULONG (r >> 8, g >> 8, b >> 8);
6274
6275 gamma_correct (f, &pixel);
6276 return pixel;
6277}
6278#endif /* MAC_TODO */
6279
6280
6281/***********************************************************************
6282 Algorithms
6283 ***********************************************************************/
6284
6285static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int));
6286static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *));
6287static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int));
6288
6289/* Non-zero means draw a cross on images having `:conversion
6290 disabled'. */
6291
6292int cross_disabled_images;
6293
6294/* Edge detection matrices for different edge-detection
6295 strategies. */
6296
6297static int emboss_matrix[9] = {
6298 /* x - 1 x x + 1 */
6299 2, -1, 0, /* y - 1 */
6300 -1, 0, 1, /* y */
6301 0, 1, -2 /* y + 1 */
6302};
6303
6304static int laplace_matrix[9] = {
6305 /* x - 1 x x + 1 */
6306 1, 0, 0, /* y - 1 */
6307 0, 0, 0, /* y */
6308 0, 0, -1 /* y + 1 */
6309};
6310
6311/* Value is the intensity of the color whose red/green/blue values
6312 are R, G, and B. */
6313
6314#define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6)
6315
6316
6317/* On frame F, return an array of XColor structures describing image
6318 IMG->pixmap. Each XColor structure has its pixel color set. RGB_P
6319 non-zero means also fill the red/green/blue members of the XColor
6320 structures. Value is a pointer to the array of XColors structures,
6321 allocated with xmalloc; it must be freed by the caller. */
6322
6323static XColor *
6324x_to_xcolors (f, img, rgb_p)
6325 struct frame *f;
6326 struct image *img;
6327 int rgb_p;
6328{
6329 int x, y;
6330 XColor *colors, *p;
6331 XImagePtr ximg;
6332
6333 colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
6334
6335 /* Get the X image IMG->pixmap. */
6336 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
6337 0, 0, img->width, img->height, ~0, ZPixmap);
6338
6339 /* Fill the `pixel' members of the XColor array. I wished there
6340 were an easy and portable way to circumvent XGetPixel. */
6341 p = colors;
6342 for (y = 0; y < img->height; ++y)
6343 {
6344 XColor *row = p;
6345
6346 for (x = 0; x < img->width; ++x, ++p)
6347 {
6348 p->pixel = XGetPixel (ximg, x, y);
6349
6350 if (rgb_p)
6351 {
6352 p->red = RED16_FROM_ULONG (p->pixel);
6353 p->green = GREEN16_FROM_ULONG (p->pixel);
6354 p->blue = BLUE16_FROM_ULONG (p->pixel);
6355 }
6356 }
6357 }
6358
6359 XDestroyImage (ximg);
6360 return colors;
6361}
6362
6363
6364/* Create IMG->pixmap from an array COLORS of XColor structures, whose
6365 RGB members are set. F is the frame on which this all happens.
6366 COLORS will be freed; an existing IMG->pixmap will be freed, too. */
6367
6368static void
6369x_from_xcolors (f, img, colors)
6370 struct frame *f;
6371 struct image *img;
6372 XColor *colors;
6373{
6374 int x, y;
6375 XImagePtr oimg;
6376 Pixmap pixmap;
6377 XColor *p;
6378
6379#if 0 /* TODO: color tables. */
6380 init_color_table ();
6381#endif
6382
6383 x_create_x_image_and_pixmap (f, img->width, img->height, 0,
6384 &oimg, &pixmap);
6385 p = colors;
6386 for (y = 0; y < img->height; ++y)
6387 for (x = 0; x < img->width; ++x, ++p)
6388 {
6389 unsigned long pixel;
6390 pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
6391 XPutPixel (oimg, x, y, pixel);
6392 }
6393
6394 xfree (colors);
6395 x_clear_image_1 (f, img, 1, 0, 1);
6396
6397 x_put_x_image (f, oimg, pixmap, img->width, img->height);
6398 x_destroy_x_image (oimg);
6399 img->pixmap = pixmap;
6400#if 0 /* TODO: color tables. */
6401 img->colors = colors_in_color_table (&img->ncolors);
6402 free_color_table ();
6403#endif
6404}
6405
6406
6407/* On frame F, perform edge-detection on image IMG.
6408
6409 MATRIX is a nine-element array specifying the transformation
6410 matrix. See emboss_matrix for an example.
6411
6412 COLOR_ADJUST is a color adjustment added to each pixel of the
6413 outgoing image. */
6414
6415static void
6416x_detect_edges (f, img, matrix, color_adjust)
6417 struct frame *f;
6418 struct image *img;
6419 int matrix[9], color_adjust;
6420{
6421 XColor *colors = x_to_xcolors (f, img, 1);
6422 XColor *new, *p;
6423 int x, y, i, sum;
6424
6425 for (i = sum = 0; i < 9; ++i)
6426 sum += abs (matrix[i]);
6427
6428#define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))
6429
6430 new = (XColor *) xmalloc (img->width * img->height * sizeof *new);
6431
6432 for (y = 0; y < img->height; ++y)
6433 {
6434 p = COLOR (new, 0, y);
6435 p->red = p->green = p->blue = 0xffff/2;
6436 p = COLOR (new, img->width - 1, y);
6437 p->red = p->green = p->blue = 0xffff/2;
6438 }
6439
6440 for (x = 1; x < img->width - 1; ++x)
6441 {
6442 p = COLOR (new, x, 0);
6443 p->red = p->green = p->blue = 0xffff/2;
6444 p = COLOR (new, x, img->height - 1);
6445 p->red = p->green = p->blue = 0xffff/2;
6446 }
6447
6448 for (y = 1; y < img->height - 1; ++y)
6449 {
6450 p = COLOR (new, 1, y);
6451
6452 for (x = 1; x < img->width - 1; ++x, ++p)
6453 {
6454 int r, g, b, y1, x1;
6455
6456 r = g = b = i = 0;
6457 for (y1 = y - 1; y1 < y + 2; ++y1)
6458 for (x1 = x - 1; x1 < x + 2; ++x1, ++i)
6459 if (matrix[i])
6460 {
6461 XColor *t = COLOR (colors, x1, y1);
6462 r += matrix[i] * t->red;
6463 g += matrix[i] * t->green;
6464 b += matrix[i] * t->blue;
6465 }
6466
6467 r = (r / sum + color_adjust) & 0xffff;
6468 g = (g / sum + color_adjust) & 0xffff;
6469 b = (b / sum + color_adjust) & 0xffff;
6470 p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b);
6471 }
6472 }
6473
6474 xfree (colors);
6475 x_from_xcolors (f, img, new);
6476
6477#undef COLOR
6478}
6479
6480
6481/* Perform the pre-defined `emboss' edge-detection on image IMG
6482 on frame F. */
6483
6484static void
6485x_emboss (f, img)
6486 struct frame *f;
6487 struct image *img;
6488{
6489 x_detect_edges (f, img, emboss_matrix, 0xffff / 2);
6490}
6491
6492
6493/* Perform the pre-defined `laplace' edge-detection on image IMG
6494 on frame F. */
6495
6496static void
6497x_laplace (f, img)
6498 struct frame *f;
6499 struct image *img;
6500{
6501 x_detect_edges (f, img, laplace_matrix, 45000);
6502}
6503
6504
6505/* Perform edge-detection on image IMG on frame F, with specified
6506 transformation matrix MATRIX and color-adjustment COLOR_ADJUST.
6507
6508 MATRIX must be either
6509
6510 - a list of at least 9 numbers in row-major form
6511 - a vector of at least 9 numbers
6512
6513 COLOR_ADJUST nil means use a default; otherwise it must be a
6514 number. */
6515
6516static void
6517x_edge_detection (f, img, matrix, color_adjust)
6518 struct frame *f;
6519 struct image *img;
6520 Lisp_Object matrix, color_adjust;
6521{
6522 int i = 0;
6523 int trans[9];
6524
6525 if (CONSP (matrix))
6526 {
6527 for (i = 0;
6528 i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix));
6529 ++i, matrix = XCDR (matrix))
6530 trans[i] = XFLOATINT (XCAR (matrix));
6531 }
6532 else if (VECTORP (matrix) && ASIZE (matrix) >= 9)
6533 {
6534 for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i)
6535 trans[i] = XFLOATINT (AREF (matrix, i));
6536 }
6537
6538 if (NILP (color_adjust))
6539 color_adjust = make_number (0xffff / 2);
6540
6541 if (i == 9 && NUMBERP (color_adjust))
6542 x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust));
6543}
6544
6545
6546/* Transform image IMG on frame F so that it looks disabled. */
6547
6548static void
6549x_disable_image (f, img)
6550 struct frame *f;
6551 struct image *img;
6552{
6553 struct x_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
6554
6555 if (dpyinfo->n_planes >= 2)
6556 {
6557 /* Color (or grayscale). Convert to gray, and equalize. Just
6558 drawing such images with a stipple can look very odd, so
6559 we're using this method instead. */
6560 XColor *colors = x_to_xcolors (f, img, 1);
6561 XColor *p, *end;
6562 const int h = 15000;
6563 const int l = 30000;
6564
6565 for (p = colors, end = colors + img->width * img->height;
6566 p < end;
6567 ++p)
6568 {
6569 int i = COLOR_INTENSITY (p->red, p->green, p->blue);
6570 int i2 = (0xffff - h - l) * i / 0xffff + l;
6571 p->red = p->green = p->blue = i2;
6572 }
6573
6574 x_from_xcolors (f, img, colors);
6575 }
6576
6577 /* Draw a cross over the disabled image, if we must or if we
6578 should. */
6579 if (dpyinfo->n_planes < 2 || cross_disabled_images)
6580 {
6581 Display *dpy = FRAME_MAC_DISPLAY (f);
6582 GC gc;
6583
6584 gc = XCreateGC (dpy, NULL /*img->pixmap*/, 0, NULL);
6585 XSetForeground (dpy, gc, BLACK_PIX_DEFAULT (f));
6586 mac_draw_line_to_pixmap (dpy, img->pixmap, gc, 0, 0,
6587 img->width - 1, img->height - 1);
6588 mac_draw_line_to_pixmap (dpy, img->pixmap, gc, 0, img->height - 1,
6589 img->width - 1, 0);
6590 XFreeGC (dpy, gc);
6591
6592 if (img->mask)
6593 {
6594 gc = XCreateGC (dpy, NULL /*img->mask*/, 0, NULL);
6595 XSetForeground (dpy, gc, PIX_MASK_DRAW (f));
6596 mac_draw_line_to_pixmap (dpy, img->mask, gc, 0, 0,
6597 img->width - 1, img->height - 1);
6598 mac_draw_line_to_pixmap (dpy, img->mask, gc, 0, img->height - 1,
6599 img->width - 1, 0);
6600 XFreeGC (dpy, gc);
6601 }
6602 }
6603}
6604
6605
6606/* Build a mask for image IMG which is used on frame F. FILE is the
6607 name of an image file, for error messages. HOW determines how to
6608 determine the background color of IMG. If it is a list '(R G B)',
6609 with R, G, and B being integers >= 0, take that as the color of the
6610 background. Otherwise, determine the background color of IMG
6611 heuristically. Value is non-zero if successful. */
6612
6613static int
6614x_build_heuristic_mask (f, img, how)
6615 struct frame *f;
6616 struct image *img;
6617 Lisp_Object how;
6618{
6619 Display *dpy = FRAME_X_DISPLAY (f);
6620 XImagePtr ximg, mask_img;
6621 int x, y, rc, use_img_background;
6622 unsigned long bg = 0;
6623
6624 if (img->mask)
6625 {
6626 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
6627 img->mask = 0;
6628 img->background_transparent_valid = 0;
6629 }
6630
6631 /* Create an image and pixmap serving as mask. */
6632 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
6633 &mask_img, &img->mask);
6634 if (!rc)
6635 return 0;
6636
6637 /* Get the X image of IMG->pixmap. */
6638 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
6639 ~0, ZPixmap);
6640
6641 /* Determine the background color of ximg. If HOW is `(R G B)'
6642 take that as color. Otherwise, use the image's background color. */
6643 use_img_background = 1;
6644
6645 if (CONSP (how))
6646 {
6647 int rgb[3], i;
6648
6649 for (i = 0; i < 3 && CONSP (how) && NATNUMP (XCAR (how)); ++i)
6650 {
6651 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
6652 how = XCDR (how);
6653 }
6654
6655 if (i == 3 && NILP (how))
6656 {
6657 char color_name[30];
6658 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
6659 bg = x_alloc_image_color (f, img, build_string (color_name), 0);
6660 use_img_background = 0;
6661 }
6662 }
6663
6664 if (use_img_background)
6665 bg = four_corners_best (ximg, img->width, img->height);
6666
6667 /* Set all bits in mask_img to 1 whose color in ximg is different
6668 from the background color bg. */
6669 for (y = 0; y < img->height; ++y)
6670 for (x = 0; x < img->width; ++x)
6671 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg ? PIX_MASK_DRAW (f) : PIX_MASK_RETAIN (f));
6672
6673 /* Fill in the background_transparent field while we have the mask handy. */
6674 image_background_transparent (img, f, mask_img);
6675
6676 /* Put mask_img into img->mask. */
6677 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
6678 x_destroy_x_image (mask_img);
6679 XDestroyImage (ximg);
6680
6681 return 1;
6682}
6683
6684
6685
6686/***********************************************************************
6687 PBM (mono, gray, color)
6688 ***********************************************************************/
6689
6690static int pbm_image_p P_ ((Lisp_Object object));
6691static int pbm_load P_ ((struct frame *f, struct image *img));
6692static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
6693
6694/* The symbol `pbm' identifying images of this type. */
6695
6696Lisp_Object Qpbm;
6697
6698/* Indices of image specification fields in gs_format, below. */
6699
6700enum pbm_keyword_index
6701{
6702 PBM_TYPE,
6703 PBM_FILE,
6704 PBM_DATA,
6705 PBM_ASCENT,
6706 PBM_MARGIN,
6707 PBM_RELIEF,
6708 PBM_ALGORITHM,
6709 PBM_HEURISTIC_MASK,
6710 PBM_MASK,
6711 PBM_FOREGROUND,
6712 PBM_BACKGROUND,
6713 PBM_LAST
6714};
6715
6716/* Vector of image_keyword structures describing the format
6717 of valid user-defined image specifications. */
6718
6719static struct image_keyword pbm_format[PBM_LAST] =
6720{
6721 {":type", IMAGE_SYMBOL_VALUE, 1},
6722 {":file", IMAGE_STRING_VALUE, 0},
6723 {":data", IMAGE_STRING_VALUE, 0},
6724 {":ascent", IMAGE_ASCENT_VALUE, 0},
6725 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6726 {":relief", IMAGE_INTEGER_VALUE, 0},
6727 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6728 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6729 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6730 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
6731 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6732};
6733
6734/* Structure describing the image type `pbm'. */
6735
6736static struct image_type pbm_type =
6737{
6738 &Qpbm,
6739 pbm_image_p,
6740 pbm_load,
6741 x_clear_image,
6742 NULL
6743};
6744
6745
6746/* Return non-zero if OBJECT is a valid PBM image specification. */
6747
6748static int
6749pbm_image_p (object)
6750 Lisp_Object object;
6751{
6752 struct image_keyword fmt[PBM_LAST];
6753
6754 bcopy (pbm_format, fmt, sizeof fmt);
6755
6756 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm))
6757 return 0;
6758
6759 /* Must specify either :data or :file. */
6760 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
6761}
6762
6763
6764/* Scan a decimal number from *S and return it. Advance *S while
6765 reading the number. END is the end of the string. Value is -1 at
6766 end of input. */
6767
6768static int
6769pbm_scan_number (s, end)
6770 unsigned char **s, *end;
6771{
6772 int c = 0, val = -1;
6773
6774 while (*s < end)
6775 {
6776 /* Skip white-space. */
6777 while (*s < end && (c = *(*s)++, isspace (c)))
6778 ;
6779
6780 if (c == '#')
6781 {
6782 /* Skip comment to end of line. */
6783 while (*s < end && (c = *(*s)++, c != '\n'))
6784 ;
6785 }
6786 else if (isdigit (c))
6787 {
6788 /* Read decimal number. */
6789 val = c - '0';
6790 while (*s < end && (c = *(*s)++, isdigit (c)))
6791 val = 10 * val + c - '0';
6792 break;
6793 }
6794 else
6795 break;
6796 }
6797
6798 return val;
6799}
6800
6801
6802/* Load PBM image IMG for use on frame F. */
6803
6804static int
6805pbm_load (f, img)
6806 struct frame *f;
6807 struct image *img;
6808{
6809 int raw_p, x, y;
6810 int width, height, max_color_idx = 0;
6811 XImagePtr ximg;
6812 Lisp_Object file, specified_file;
6813 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
6814 struct gcpro gcpro1;
6815 unsigned char *contents = NULL;
6816 unsigned char *end, *p;
6817 int size;
6818
6819 specified_file = image_spec_value (img->spec, QCfile, NULL);
6820 file = Qnil;
6821 GCPRO1 (file);
6822
6823 if (STRINGP (specified_file))
6824 {
6825 file = x_find_image_file (specified_file);
6826 if (!STRINGP (file))
6827 {
6828 image_error ("Cannot find image file `%s'", specified_file, Qnil);
6829 UNGCPRO;
6830 return 0;
6831 }
6832
6833 contents = slurp_file (SDATA (file), &size);
6834 if (contents == NULL)
6835 {
6836 image_error ("Error reading `%s'", file, Qnil);
6837 UNGCPRO;
6838 return 0;
6839 }
6840
6841 p = contents;
6842 end = contents + size;
6843 }
6844 else
6845 {
6846 Lisp_Object data;
6847 data = image_spec_value (img->spec, QCdata, NULL);
6848 p = SDATA (data);
6849 end = p + SBYTES (data);
6850 }
6851
6852 /* Check magic number. */
6853 if (end - p < 2 || *p++ != 'P')
6854 {
6855 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
6856 error:
6857 xfree (contents);
6858 UNGCPRO;
6859 return 0;
6860 }
6861
6862 switch (*p++)
6863 {
6864 case '1':
6865 raw_p = 0, type = PBM_MONO;
6866 break;
6867
6868 case '2':
6869 raw_p = 0, type = PBM_GRAY;
6870 break;
6871
6872 case '3':
6873 raw_p = 0, type = PBM_COLOR;
6874 break;
6875
6876 case '4':
6877 raw_p = 1, type = PBM_MONO;
6878 break;
6879
6880 case '5':
6881 raw_p = 1, type = PBM_GRAY;
6882 break;
6883
6884 case '6':
6885 raw_p = 1, type = PBM_COLOR;
6886 break;
6887
6888 default:
6889 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
6890 goto error;
6891 }
6892
6893 /* Read width, height, maximum color-component. Characters
6894 starting with `#' up to the end of a line are ignored. */
6895 width = pbm_scan_number (&p, end);
6896 height = pbm_scan_number (&p, end);
6897
6898 if (type != PBM_MONO)
6899 {
6900 max_color_idx = pbm_scan_number (&p, end);
6901 if (raw_p && max_color_idx > 255)
6902 max_color_idx = 255;
6903 }
6904
6905 if (width < 0
6906 || height < 0
6907 || (type != PBM_MONO && max_color_idx < 0))
6908 goto error;
6909
6910 if (!x_create_x_image_and_pixmap (f, width, height, 0,
6911 &ximg, &img->pixmap))
6912 goto error;
6913
6914#if 0 /* TODO: color tables. */
6915 /* Initialize the color hash table. */
6916 init_color_table ();
6917#endif
6918
6919 if (type == PBM_MONO)
6920 {
6921 int c = 0, g;
6922 struct image_keyword fmt[PBM_LAST];
6923 unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
6924 unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
6925
6926 /* Parse the image specification. */
6927 bcopy (pbm_format, fmt, sizeof fmt);
6928 parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
6929
6930 /* Get foreground and background colors, maybe allocate colors. */
6931 if (fmt[PBM_FOREGROUND].count
6932 && STRINGP (fmt[PBM_FOREGROUND].value))
6933 fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
6934 if (fmt[PBM_BACKGROUND].count
6935 && STRINGP (fmt[PBM_BACKGROUND].value))
6936 {
6937 bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg);
6938 img->background = bg;
6939 img->background_valid = 1;
6940 }
6941
6942 for (y = 0; y < height; ++y)
6943 for (x = 0; x < width; ++x)
6944 {
6945 if (raw_p)
6946 {
6947 if ((x & 7) == 0)
6948 c = *p++;
6949 g = c & 0x80;
6950 c <<= 1;
6951 }
6952 else
6953 g = pbm_scan_number (&p, end);
6954
6955 XPutPixel (ximg, x, y, g ? fg : bg);
6956 }
6957 }
6958 else
6959 {
6960 for (y = 0; y < height; ++y)
6961 for (x = 0; x < width; ++x)
6962 {
6963 int r, g, b;
6964
6965 if (type == PBM_GRAY)
6966 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
6967 else if (raw_p)
6968 {
6969 r = *p++;
6970 g = *p++;
6971 b = *p++;
6972 }
6973 else
6974 {
6975 r = pbm_scan_number (&p, end);
6976 g = pbm_scan_number (&p, end);
6977 b = pbm_scan_number (&p, end);
6978 }
6979
6980 if (r < 0 || g < 0 || b < 0)
6981 {
6982 x_destroy_x_image (ximg);
6983 image_error ("Invalid pixel value in image `%s'",
6984 img->spec, Qnil);
6985 goto error;
6986 }
6987
6988 /* RGB values are now in the range 0..max_color_idx.
6989 Scale this to the range 0..0xffff supported by X. */
6990 r = (double) r * 65535 / max_color_idx;
6991 g = (double) g * 65535 / max_color_idx;
6992 b = (double) b * 65535 / max_color_idx;
6993 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
6994 }
6995 }
6996
6997#if 0 /* TODO: color tables. */
6998 /* Store in IMG->colors the colors allocated for the image, and
6999 free the color table. */
7000 img->colors = colors_in_color_table (&img->ncolors);
7001 free_color_table ();
7002#endif
7003
7004 img->width = width;
7005 img->height = height;
7006
7007 /* Maybe fill in the background field while we have ximg handy. */
7008 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
7009 IMAGE_BACKGROUND (img, f, ximg);
7010
7011 /* Put the image into a pixmap. */
7012 x_put_x_image (f, ximg, img->pixmap, width, height);
7013 x_destroy_x_image (ximg);
7014
7015 UNGCPRO;
7016 xfree (contents);
7017 return 1;
7018}
7019
7020
7021
7022/***********************************************************************
7023 PNG
7024 ***********************************************************************/
7025
7026
7027/* Function prototypes. */
7028
7029static int png_image_p P_ ((Lisp_Object object));
7030static int png_load P_ ((struct frame *f, struct image *img));
7031
7032/* The symbol `png' identifying images of this type. */
7033
7034Lisp_Object Qpng;
7035
7036/* Indices of image specification fields in png_format, below. */
7037
7038enum png_keyword_index
7039{
7040 PNG_TYPE,
7041 PNG_DATA,
7042 PNG_FILE,
7043 PNG_ASCENT,
7044 PNG_MARGIN,
7045 PNG_RELIEF,
7046 PNG_ALGORITHM,
7047 PNG_HEURISTIC_MASK,
7048 PNG_MASK,
7049 PNG_BACKGROUND,
7050 PNG_LAST
7051};
7052
7053/* Vector of image_keyword structures describing the format
7054 of valid user-defined image specifications. */
7055
7056static struct image_keyword png_format[PNG_LAST] =
7057{
7058 {":type", IMAGE_SYMBOL_VALUE, 1},
7059 {":data", IMAGE_STRING_VALUE, 0},
7060 {":file", IMAGE_STRING_VALUE, 0},
7061 {":ascent", IMAGE_ASCENT_VALUE, 0},
7062 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
7063 {":relief", IMAGE_INTEGER_VALUE, 0},
7064 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7065 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7066 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7067 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
7068};
7069
7070/* Structure describing the image type `png'. */
7071
7072static struct image_type png_type =
7073{
7074 &Qpng,
7075 png_image_p,
7076 png_load,
7077 x_clear_image,
7078 NULL
7079};
7080
7081
7082/* Return non-zero if OBJECT is a valid PNG image specification. */
7083
7084static int
7085png_image_p (object)
7086 Lisp_Object object;
7087{
7088 struct image_keyword fmt[PNG_LAST];
7089 bcopy (png_format, fmt, sizeof fmt);
7090
7091 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng))
7092 return 0;
7093
7094 /* Must specify either the :data or :file keyword. */
7095 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
7096}
7097
7098
7099#ifndef HAVE_PNG
7100static int
7101png_load (f, img)
7102 struct frame *f;
7103 struct image *img;
7104{
7105#ifdef MAC_OSX
7106 if (MyCGImageCreateWithPNGDataProvider)
7107 return image_load_quartz2d (f, img, 1);
7108 else
7109#endif
7110 return image_load_quicktime (f, img, kQTFileTypePNG);
7111}
7112#else
7113
7114#if defined HAVE_LIBPNG_PNG_H
7115# include <libpng/png.h>
7116#else
7117# include <png.h>
7118#endif
7119
7120/* Error and warning handlers installed when the PNG library
7121 is initialized. */
7122
7123static void
7124my_png_error (png_ptr, msg)
7125 png_struct *png_ptr;
7126 char *msg;
7127{
7128 xassert (png_ptr != NULL);
7129 image_error ("PNG error: %s", build_string (msg), Qnil);
7130 longjmp (png_ptr->jmpbuf, 1);
7131}
7132
7133
7134static void
7135my_png_warning (png_ptr, msg)
7136 png_struct *png_ptr;
7137 char *msg;
7138{
7139 xassert (png_ptr != NULL);
7140 image_error ("PNG warning: %s", build_string (msg), Qnil);
7141}
7142
7143/* Memory source for PNG decoding. */
7144
7145struct png_memory_storage
7146{
7147 unsigned char *bytes; /* The data */
7148 size_t len; /* How big is it? */
7149 int index; /* Where are we? */
7150};
7151
7152
7153/* Function set as reader function when reading PNG image from memory.
7154 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
7155 bytes from the input to DATA. */
7156
7157static void
7158png_read_from_memory (png_ptr, data, length)
7159 png_structp png_ptr;
7160 png_bytep data;
7161 png_size_t length;
7162{
7163 struct png_memory_storage *tbr
7164 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
7165
7166 if (length > tbr->len - tbr->index)
7167 png_error (png_ptr, "Read error");
7168
7169 bcopy (tbr->bytes + tbr->index, data, length);
7170 tbr->index = tbr->index + length;
7171}
7172
7173/* Load PNG image IMG for use on frame F. Value is non-zero if
7174 successful. */
7175
7176static int
7177png_load (f, img)
7178 struct frame *f;
7179 struct image *img;
7180{
7181 Lisp_Object file, specified_file;
7182 Lisp_Object specified_data;
7183 int x, y, i;
7184 XImagePtr ximg, mask_img = NULL;
7185 struct gcpro gcpro1;
7186 png_struct *png_ptr = NULL;
7187 png_info *info_ptr = NULL, *end_info = NULL;
7188 FILE *volatile fp = NULL;
7189 png_byte sig[8];
7190 png_byte * volatile pixels = NULL;
7191 png_byte ** volatile rows = NULL;
7192 png_uint_32 width, height;
7193 int bit_depth, color_type, interlace_type;
7194 png_byte channels;
7195 png_uint_32 row_bytes;
7196 int transparent_p;
7197 double screen_gamma;
7198 struct png_memory_storage tbr; /* Data to be read */
7199
7200 /* Find out what file to load. */
7201 specified_file = image_spec_value (img->spec, QCfile, NULL);
7202 specified_data = image_spec_value (img->spec, QCdata, NULL);
7203 file = Qnil;
7204 GCPRO1 (file);
7205
7206 if (NILP (specified_data))
7207 {
7208 file = x_find_image_file (specified_file);
7209 if (!STRINGP (file))
7210 {
7211 image_error ("Cannot find image file `%s'", specified_file, Qnil);
7212 UNGCPRO;
7213 return 0;
7214 }
7215
7216 /* Open the image file. */
7217 fp = fopen (SDATA (file), "rb");
7218 if (!fp)
7219 {
7220 image_error ("Cannot open image file `%s'", file, Qnil);
7221 UNGCPRO;
7222 fclose (fp);
7223 return 0;
7224 }
7225
7226 /* Check PNG signature. */
7227 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
7228 || !png_check_sig (sig, sizeof sig))
7229 {
7230 image_error ("Not a PNG file: `%s'", file, Qnil);
7231 UNGCPRO;
7232 fclose (fp);
7233 return 0;
7234 }
7235 }
7236 else
7237 {
7238 /* Read from memory. */
7239 tbr.bytes = SDATA (specified_data);
7240 tbr.len = SBYTES (specified_data);
7241 tbr.index = 0;
7242
7243 /* Check PNG signature. */
7244 if (tbr.len < sizeof sig
7245 || !png_check_sig (tbr.bytes, sizeof sig))
7246 {
7247 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
7248 UNGCPRO;
7249 return 0;
7250 }
7251
7252 /* Need to skip past the signature. */
7253 tbr.bytes += sizeof (sig);
7254 }
7255
7256 /* Initialize read and info structs for PNG lib. */
7257 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
7258 my_png_error, my_png_warning);
7259 if (!png_ptr)
7260 {
7261 if (fp) fclose (fp);
7262 UNGCPRO;
7263 return 0;
7264 }
7265
7266 info_ptr = png_create_info_struct (png_ptr);
7267 if (!info_ptr)
7268 {
7269 png_destroy_read_struct (&png_ptr, NULL, NULL);
7270 if (fp) fclose (fp);
7271 UNGCPRO;
7272 return 0;
7273 }
7274
7275 end_info = png_create_info_struct (png_ptr);
7276 if (!end_info)
7277 {
7278 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
7279 if (fp) fclose (fp);
7280 UNGCPRO;
7281 return 0;
7282 }
7283
7284 /* Set error jump-back. We come back here when the PNG library
7285 detects an error. */
7286 if (setjmp (png_ptr->jmpbuf))
7287 {
7288 error:
7289 if (png_ptr)
7290 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
7291 xfree (pixels);
7292 xfree (rows);
7293 if (fp) fclose (fp);
7294 UNGCPRO;
7295 return 0;
7296 }
7297
7298 /* Read image info. */
7299 if (!NILP (specified_data))
7300 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
7301 else
7302 png_init_io (png_ptr, fp);
7303
7304 png_set_sig_bytes (png_ptr, sizeof sig);
7305 png_read_info (png_ptr, info_ptr);
7306 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
7307 &interlace_type, NULL, NULL);
7308
7309 /* If image contains simply transparency data, we prefer to
7310 construct a clipping mask. */
7311 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
7312 transparent_p = 1;
7313 else
7314 transparent_p = 0;
7315
7316 /* This function is easier to write if we only have to handle
7317 one data format: RGB or RGBA with 8 bits per channel. Let's
7318 transform other formats into that format. */
7319
7320 /* Strip more than 8 bits per channel. */
7321 if (bit_depth == 16)
7322 png_set_strip_16 (png_ptr);
7323
7324 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
7325 if available. */
7326 png_set_expand (png_ptr);
7327
7328 /* Convert grayscale images to RGB. */
7329 if (color_type == PNG_COLOR_TYPE_GRAY
7330 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
7331 png_set_gray_to_rgb (png_ptr);
7332
7333 screen_gamma = (f->gamma ? 1 / f->gamma / 0.45455 : 2.2);
7334
7335#if 0 /* Avoid double gamma correction for PNG images. */
7336 { /* Tell the PNG lib to handle gamma correction for us. */
7337 int intent;
7338 double image_gamma;
7339#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
7340 if (png_get_sRGB (png_ptr, info_ptr, &intent))
7341 /* The libpng documentation says this is right in this case. */
7342 png_set_gamma (png_ptr, screen_gamma, 0.45455);
7343 else
7344#endif
7345 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
7346 /* Image contains gamma information. */
7347 png_set_gamma (png_ptr, screen_gamma, image_gamma);
7348 else
7349 /* Use the standard default for the image gamma. */
7350 png_set_gamma (png_ptr, screen_gamma, 0.45455);
7351 }
7352#endif /* if 0 */
7353
7354 /* Handle alpha channel by combining the image with a background
7355 color. Do this only if a real alpha channel is supplied. For
7356 simple transparency, we prefer a clipping mask. */
7357 if (!transparent_p)
7358 {
7359 png_color_16 *image_bg;
7360 Lisp_Object specified_bg
7361 = image_spec_value (img->spec, QCbackground, NULL);
7362
7363 if (STRINGP (specified_bg))
7364 /* The user specified `:background', use that. */
7365 {
7366 XColor color;
7367 if (mac_defined_color (f, SDATA (specified_bg), &color, 0))
7368 {
7369 png_color_16 user_bg;
7370
7371 bzero (&user_bg, sizeof user_bg);
7372 user_bg.red = color.red >> 8;
7373 user_bg.green = color.green >> 8;
7374 user_bg.blue = color.blue >> 8;
7375
7376 png_set_background (png_ptr, &user_bg,
7377 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
7378 }
7379 }
7380 else if (png_get_bKGD (png_ptr, info_ptr, &image_bg))
7381 /* Image contains a background color with which to
7382 combine the image. */
7383 png_set_background (png_ptr, image_bg,
7384 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
7385 else
7386 {
7387 /* Image does not contain a background color with which
7388 to combine the image data via an alpha channel. Use
7389 the frame's background instead. */
7390 unsigned long color;
7391 png_color_16 frame_background;
7392 color = FRAME_BACKGROUND_PIXEL (f);
7393#if 0 /* TODO : Colormap support. */
7394 Colormap cmap;
7395
7396 cmap = FRAME_X_COLORMAP (f);
7397 x_query_color (f, &color);
7398#endif
7399 bzero (&frame_background, sizeof frame_background);
7400 frame_background.red = RED_FROM_ULONG (color);
7401 frame_background.green = GREEN_FROM_ULONG (color);
7402 frame_background.blue = BLUE_FROM_ULONG (color);
7403
7404 png_set_background (png_ptr, &frame_background,
7405 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
7406 }
7407 }
7408
7409 /* Update info structure. */
7410 png_read_update_info (png_ptr, info_ptr);
7411
7412 /* Get number of channels. Valid values are 1 for grayscale images
7413 and images with a palette, 2 for grayscale images with transparency
7414 information (alpha channel), 3 for RGB images, and 4 for RGB
7415 images with alpha channel, i.e. RGBA. If conversions above were
7416 sufficient we should only have 3 or 4 channels here. */
7417 channels = png_get_channels (png_ptr, info_ptr);
7418 xassert (channels == 3 || channels == 4);
7419
7420 /* Number of bytes needed for one row of the image. */
7421 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
7422
7423 /* Allocate memory for the image. */
7424 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
7425 rows = (png_byte **) xmalloc (height * sizeof *rows);
7426 for (i = 0; i < height; ++i)
7427 rows[i] = pixels + i * row_bytes;
7428
7429 /* Read the entire image. */
7430 png_read_image (png_ptr, rows);
7431 png_read_end (png_ptr, info_ptr);
7432 if (fp)
7433 {
7434 fclose (fp);
7435 fp = NULL;
7436 }
7437
7438 /* Create the X image and pixmap. */
7439 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
7440 &img->pixmap))
7441 goto error;
7442
7443 /* Create an image and pixmap serving as mask if the PNG image
7444 contains an alpha channel. */
7445 if (channels == 4
7446 && !transparent_p
7447 && !x_create_x_image_and_pixmap (f, width, height, 1,
7448 &mask_img, &img->mask))
7449 {
7450 x_destroy_x_image (ximg);
7451 XFreePixmap (FRAME_MAC_DISPLAY (f), img->pixmap);
7452 img->pixmap = NULL;
7453 goto error;
7454 }
7455
7456 /* Fill the X image and mask from PNG data. */
7457#if 0 /* TODO: Color tables. */
7458 init_color_table ();
7459#endif
7460
7461 for (y = 0; y < height; ++y)
7462 {
7463 png_byte *p = rows[y];
7464
7465 for (x = 0; x < width; ++x)
7466 {
7467 unsigned r, g, b;
7468
7469 r = *p++ << 8;
7470 g = *p++ << 8;
7471 b = *p++ << 8;
7472 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
7473
7474 /* An alpha channel, aka mask channel, associates variable
7475 transparency with an image. Where other image formats
7476 support binary transparency---fully transparent or fully
7477 opaque---PNG allows up to 254 levels of partial transparency.
7478 The PNG library implements partial transparency by combining
7479 the image with a specified background color.
7480
7481 I'm not sure how to handle this here nicely: because the
7482 background on which the image is displayed may change, for
7483 real alpha channel support, it would be necessary to create
7484 a new image for each possible background.
7485
7486 What I'm doing now is that a mask is created if we have
7487 boolean transparency information. Otherwise I'm using
7488 the frame's background color to combine the image with. */
7489
7490 if (channels == 4)
7491 {
7492 if (mask_img)
7493 XPutPixel (mask_img, x, y, *p > 0 ? PIX_MASK_DRAW (f) : PIX_MASK_RETAIN (f));
7494 ++p;
7495 }
7496 }
7497 }
7498
7499 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
7500 /* Set IMG's background color from the PNG image, unless the user
7501 overrode it. */
7502 {
7503 png_color_16 *bg;
7504 if (png_get_bKGD (png_ptr, info_ptr, &bg))
7505 {
7506 img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue);
7507 img->background_valid = 1;
7508 }
7509 }
7510
7511#if 0 /* TODO: Color tables. */
7512 /* Remember colors allocated for this image. */
7513 img->colors = colors_in_color_table (&img->ncolors);
7514 free_color_table ();
7515#endif
7516
7517 /* Clean up. */
7518 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
7519 xfree (rows);
7520 xfree (pixels);
7521
7522 img->width = width;
7523 img->height = height;
7524
7525 /* Maybe fill in the background field while we have ximg handy. */
7526 IMAGE_BACKGROUND (img, f, ximg);
7527
7528 /* Put the image into the pixmap, then free the X image and its buffer. */
7529 x_put_x_image (f, ximg, img->pixmap, width, height);
7530 x_destroy_x_image (ximg);
7531
7532 /* Same for the mask. */
7533 if (mask_img)
7534 {
7535 /* Fill in the background_transparent field while we have the mask
7536 handy. */
7537 image_background_transparent (img, f, mask_img);
7538
7539 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
7540 x_destroy_x_image (mask_img);
7541 }
7542
7543 UNGCPRO;
7544 return 1;
7545}
7546
7547#endif /* HAVE_PNG */
7548
7549
7550
7551/***********************************************************************
7552 JPEG
7553 ***********************************************************************/
7554
7555static int jpeg_image_p P_ ((Lisp_Object object));
7556static int jpeg_load P_ ((struct frame *f, struct image *img));
7557
7558/* The symbol `jpeg' identifying images of this type. */
7559
7560Lisp_Object Qjpeg;
7561
7562/* Indices of image specification fields in gs_format, below. */
7563
7564enum jpeg_keyword_index
7565{
7566 JPEG_TYPE,
7567 JPEG_DATA,
7568 JPEG_FILE,
7569 JPEG_ASCENT,
7570 JPEG_MARGIN,
7571 JPEG_RELIEF,
7572 JPEG_ALGORITHM,
7573 JPEG_HEURISTIC_MASK,
7574 JPEG_MASK,
7575 JPEG_BACKGROUND,
7576 JPEG_LAST
7577};
7578
7579/* Vector of image_keyword structures describing the format
7580 of valid user-defined image specifications. */
7581
7582static struct image_keyword jpeg_format[JPEG_LAST] =
7583{
7584 {":type", IMAGE_SYMBOL_VALUE, 1},
7585 {":data", IMAGE_STRING_VALUE, 0},
7586 {":file", IMAGE_STRING_VALUE, 0},
7587 {":ascent", IMAGE_ASCENT_VALUE, 0},
7588 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
7589 {":relief", IMAGE_INTEGER_VALUE, 0},
7590 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7591 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7592 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7593 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
7594};
7595
7596/* Structure describing the image type `jpeg'. */
7597
7598static struct image_type jpeg_type =
7599{
7600 &Qjpeg,
7601 jpeg_image_p,
7602 jpeg_load,
7603 x_clear_image,
7604 NULL
7605};
7606
7607
7608/* Return non-zero if OBJECT is a valid JPEG image specification. */
7609
7610static int
7611jpeg_image_p (object)
7612 Lisp_Object object;
7613{
7614 struct image_keyword fmt[JPEG_LAST];
7615
7616 bcopy (jpeg_format, fmt, sizeof fmt);
7617
7618 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg))
7619 return 0;
7620
7621 /* Must specify either the :data or :file keyword. */
7622 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
7623}
7624
7625
7626#ifndef HAVE_JPEG
7627static int
7628jpeg_load (f, img)
7629 struct frame *f;
7630 struct image *img;
7631{
7632#ifdef MAC_OSX
7633 return image_load_quartz2d (f, img, 0);
7634#else
7635 return image_load_quicktime (f, img, kQTFileTypeJPEG);
7636#endif
7637}
7638#else
7639
7640/* Work around a warning about HAVE_STDLIB_H being redefined in
7641 jconfig.h. */
7642#ifdef HAVE_STDLIB_H
7643#define HAVE_STDLIB_H_1
7644#undef HAVE_STDLIB_H
7645#endif /* HAVE_STLIB_H */
7646
7647#include <jpeglib.h>
7648#include <jerror.h>
7649#include <setjmp.h>
7650
7651#ifdef HAVE_STLIB_H_1
7652#define HAVE_STDLIB_H 1
7653#endif
7654
7655struct my_jpeg_error_mgr
7656{
7657 struct jpeg_error_mgr pub;
7658 jmp_buf setjmp_buffer;
7659};
7660
7661
7662static void
7663my_error_exit (cinfo)
7664 j_common_ptr cinfo;
7665{
7666 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
7667 longjmp (mgr->setjmp_buffer, 1);
7668}
7669
7670
7671/* Init source method for JPEG data source manager. Called by
7672 jpeg_read_header() before any data is actually read. See
7673 libjpeg.doc from the JPEG lib distribution. */
7674
7675static void
7676our_init_source (cinfo)
7677 j_decompress_ptr cinfo;
7678{
7679}
7680
7681
7682/* Fill input buffer method for JPEG data source manager. Called
7683 whenever more data is needed. We read the whole image in one step,
7684 so this only adds a fake end of input marker at the end. */
7685
7686static boolean
7687our_fill_input_buffer (cinfo)
7688 j_decompress_ptr cinfo;
7689{
7690 /* Insert a fake EOI marker. */
7691 struct jpeg_source_mgr *src = cinfo->src;
7692 static JOCTET buffer[2];
7693
7694 buffer[0] = (JOCTET) 0xFF;
7695 buffer[1] = (JOCTET) JPEG_EOI;
7696
7697 src->next_input_byte = buffer;
7698 src->bytes_in_buffer = 2;
7699 return TRUE;
7700}
7701
7702
7703/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
7704 is the JPEG data source manager. */
7705
7706static void
7707our_skip_input_data (cinfo, num_bytes)
7708 j_decompress_ptr cinfo;
7709 long num_bytes;
7710{
7711 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
7712
7713 if (src)
7714 {
7715 if (num_bytes > src->bytes_in_buffer)
7716 ERREXIT (cinfo, JERR_INPUT_EOF);
7717
7718 src->bytes_in_buffer -= num_bytes;
7719 src->next_input_byte += num_bytes;
7720 }
7721}
7722
7723
7724/* Method to terminate data source. Called by
7725 jpeg_finish_decompress() after all data has been processed. */
7726
7727static void
7728our_term_source (cinfo)
7729 j_decompress_ptr cinfo;
7730{
7731}
7732
7733
7734/* Set up the JPEG lib for reading an image from DATA which contains
7735 LEN bytes. CINFO is the decompression info structure created for
7736 reading the image. */
7737
7738static void
7739jpeg_memory_src (cinfo, data, len)
7740 j_decompress_ptr cinfo;
7741 JOCTET *data;
7742 unsigned int len;
7743{
7744 struct jpeg_source_mgr *src;
7745
7746 if (cinfo->src == NULL)
7747 {
7748 /* First time for this JPEG object? */
7749 cinfo->src = (struct jpeg_source_mgr *)
7750 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
7751 sizeof (struct jpeg_source_mgr));
7752 src = (struct jpeg_source_mgr *) cinfo->src;
7753 src->next_input_byte = data;
7754 }
7755
7756 src = (struct jpeg_source_mgr *) cinfo->src;
7757 src->init_source = our_init_source;
7758 src->fill_input_buffer = our_fill_input_buffer;
7759 src->skip_input_data = our_skip_input_data;
7760 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
7761 src->term_source = our_term_source;
7762 src->bytes_in_buffer = len;
7763 src->next_input_byte = data;
7764}
7765
7766
7767/* Load image IMG for use on frame F. Patterned after example.c
7768 from the JPEG lib. */
7769
7770static int
7771jpeg_load (f, img)
7772 struct frame *f;
7773 struct image *img;
7774{
7775 struct jpeg_decompress_struct cinfo;
7776 struct my_jpeg_error_mgr mgr;
7777 Lisp_Object file, specified_file;
7778 Lisp_Object specified_data;
7779 FILE * volatile fp = NULL;
7780 JSAMPARRAY buffer;
7781 int row_stride, x, y;
7782 XImagePtr ximg = NULL;
7783 int rc;
7784 unsigned long *colors;
7785 int width, height;
7786 struct gcpro gcpro1;
7787
7788 /* Open the JPEG file. */
7789 specified_file = image_spec_value (img->spec, QCfile, NULL);
7790 specified_data = image_spec_value (img->spec, QCdata, NULL);
7791 file = Qnil;
7792 GCPRO1 (file);
7793
7794 if (NILP (specified_data))
7795 {
7796 file = x_find_image_file (specified_file);
7797 if (!STRINGP (file))
7798 {
7799 image_error ("Cannot find image file `%s'", specified_file, Qnil);
7800 UNGCPRO;
7801 return 0;
7802 }
7803
7804 fp = fopen (SDATA (file), "r");
7805 if (fp == NULL)
7806 {
7807 image_error ("Cannot open `%s'", file, Qnil);
7808 UNGCPRO;
7809 return 0;
7810 }
7811 }
7812
7813 /* Customize libjpeg's error handling to call my_error_exit when an
7814 error is detected. This function will perform a longjmp. */
7815 cinfo.err = jpeg_std_error (&mgr.pub);
7816 mgr.pub.error_exit = my_error_exit;
7817
7818 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
7819 {
7820 if (rc == 1)
7821 {
7822 /* Called from my_error_exit. Display a JPEG error. */
7823 char buffer[JMSG_LENGTH_MAX];
7824 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
7825 image_error ("Error reading JPEG image `%s': %s", img->spec,
7826 build_string (buffer));
7827 }
7828
7829 /* Close the input file and destroy the JPEG object. */
7830 if (fp)
7831 fclose ((FILE *) fp);
7832 jpeg_destroy_decompress (&cinfo);
7833
7834 /* If we already have an XImage, free that. */
7835 x_destroy_x_image (ximg);
7836
7837 /* Free pixmap and colors. */
7838 x_clear_image (f, img);
7839
7840 UNGCPRO;
7841 return 0;
7842 }
7843
7844 /* Create the JPEG decompression object. Let it read from fp.
7845 Read the JPEG image header. */
7846 jpeg_create_decompress (&cinfo);
7847
7848 if (NILP (specified_data))
7849 jpeg_stdio_src (&cinfo, (FILE *) fp);
7850 else
7851 jpeg_memory_src (&cinfo, SDATA (specified_data),
7852 SBYTES (specified_data));
7853
7854 jpeg_read_header (&cinfo, TRUE);
7855
7856 /* Customize decompression so that color quantization will be used.
7857 Start decompression. */
7858 cinfo.quantize_colors = TRUE;
7859 jpeg_start_decompress (&cinfo);
7860 width = img->width = cinfo.output_width;
7861 height = img->height = cinfo.output_height;
7862
7863 /* Create X image and pixmap. */
7864 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
7865 longjmp (mgr.setjmp_buffer, 2);
7866
7867 /* Allocate colors. When color quantization is used,
7868 cinfo.actual_number_of_colors has been set with the number of
7869 colors generated, and cinfo.colormap is a two-dimensional array
7870 of color indices in the range 0..cinfo.actual_number_of_colors.
7871 No more than 255 colors will be generated. */
7872 {
7873 int i, ir, ig, ib;
7874
7875 if (cinfo.out_color_components > 2)
7876 ir = 0, ig = 1, ib = 2;
7877 else if (cinfo.out_color_components > 1)
7878 ir = 0, ig = 1, ib = 0;
7879 else
7880 ir = 0, ig = 0, ib = 0;
7881
7882#if 0 /* TODO: Color tables. */
7883 /* Use the color table mechanism because it handles colors that
7884 cannot be allocated nicely. Such colors will be replaced with
7885 a default color, and we don't have to care about which colors
7886 can be freed safely, and which can't. */
7887 init_color_table ();
7888#endif
7889 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
7890 * sizeof *colors);
7891
7892 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
7893 {
7894 /* Multiply RGB values with 255 because X expects RGB values
7895 in the range 0..0xffff. */
7896 int r = cinfo.colormap[ir][i] << 8;
7897 int g = cinfo.colormap[ig][i] << 8;
7898 int b = cinfo.colormap[ib][i] << 8;
7899 colors[i] = lookup_rgb_color (f, r, g, b);
7900 }
7901
7902#if 0 /* TODO: Color tables. */
7903 /* Remember those colors actually allocated. */
7904 img->colors = colors_in_color_table (&img->ncolors);
7905 free_color_table ();
7906#endif
7907 }
7908
7909 /* Read pixels. */
7910 row_stride = width * cinfo.output_components;
7911 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
7912 row_stride, 1);
7913 for (y = 0; y < height; ++y)
7914 {
7915 jpeg_read_scanlines (&cinfo, buffer, 1);
7916 for (x = 0; x < cinfo.output_width; ++x)
7917 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
7918 }
7919
7920 /* Clean up. */
7921 jpeg_finish_decompress (&cinfo);
7922 jpeg_destroy_decompress (&cinfo);
7923 if (fp)
7924 fclose ((FILE *) fp);
7925
7926 /* Maybe fill in the background field while we have ximg handy. */
7927 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
7928 IMAGE_BACKGROUND (img, f, ximg);
7929
7930 /* Put the image into the pixmap. */
7931 x_put_x_image (f, ximg, img->pixmap, width, height);
7932 x_destroy_x_image (ximg);
7933 UNGCPRO;
7934 return 1;
7935}
7936
7937#endif /* HAVE_JPEG */
7938
7939
7940
7941/***********************************************************************
7942 TIFF
7943 ***********************************************************************/
7944
7945static int tiff_image_p P_ ((Lisp_Object object));
7946static int tiff_load P_ ((struct frame *f, struct image *img));
7947
7948/* The symbol `tiff' identifying images of this type. */
7949
7950Lisp_Object Qtiff;
7951
7952/* Indices of image specification fields in tiff_format, below. */
7953
7954enum tiff_keyword_index
7955{
7956 TIFF_TYPE,
7957 TIFF_DATA,
7958 TIFF_FILE,
7959 TIFF_ASCENT,
7960 TIFF_MARGIN,
7961 TIFF_RELIEF,
7962 TIFF_ALGORITHM,
7963 TIFF_HEURISTIC_MASK,
7964 TIFF_MASK,
7965 TIFF_BACKGROUND,
7966 TIFF_LAST
7967};
7968
7969/* Vector of image_keyword structures describing the format
7970 of valid user-defined image specifications. */
7971
7972static struct image_keyword tiff_format[TIFF_LAST] =
7973{
7974 {":type", IMAGE_SYMBOL_VALUE, 1},
7975 {":data", IMAGE_STRING_VALUE, 0},
7976 {":file", IMAGE_STRING_VALUE, 0},
7977 {":ascent", IMAGE_ASCENT_VALUE, 0},
7978 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
7979 {":relief", IMAGE_INTEGER_VALUE, 0},
7980 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7981 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7982 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7983 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
7984};
7985
7986/* Structure describing the image type `tiff'. */
7987
7988static struct image_type tiff_type =
7989{
7990 &Qtiff,
7991 tiff_image_p,
7992 tiff_load,
7993 x_clear_image,
7994 NULL
7995};
7996
7997
7998/* Return non-zero if OBJECT is a valid TIFF image specification. */
7999
8000static int
8001tiff_image_p (object)
8002 Lisp_Object object;
8003{
8004 struct image_keyword fmt[TIFF_LAST];
8005 bcopy (tiff_format, fmt, sizeof fmt);
8006
8007 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff))
8008 return 0;
8009
8010 /* Must specify either the :data or :file keyword. */
8011 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
8012}
8013
8014#ifndef HAVE_TIFF
8015
8016static int
8017tiff_load (f, img)
8018 struct frame *f;
8019 struct image *img;
8020{
8021 return image_load_quicktime (f, img, kQTFileTypeTIFF);
8022}
8023
8024#else
8025
8026#include <tiffio.h>
8027
8028/* Reading from a memory buffer for TIFF images Based on the PNG
8029 memory source, but we have to provide a lot of extra functions.
8030 Blah.
8031
8032 We really only need to implement read and seek, but I am not
8033 convinced that the TIFF library is smart enough not to destroy
8034 itself if we only hand it the function pointers we need to
8035 override. */
8036
8037typedef struct
8038{
8039 unsigned char *bytes;
8040 size_t len;
8041 int index;
8042}
8043tiff_memory_source;
8044
8045
8046static size_t
8047tiff_read_from_memory (data, buf, size)
8048 thandle_t data;
8049 tdata_t buf;
8050 tsize_t size;
8051{
8052 tiff_memory_source *src = (tiff_memory_source *) data;
8053
8054 if (size > src->len - src->index)
8055 return (size_t) -1;
8056 bcopy (src->bytes + src->index, buf, size);
8057 src->index += size;
8058 return size;
8059}
8060
8061
8062static size_t
8063tiff_write_from_memory (data, buf, size)
8064 thandle_t data;
8065 tdata_t buf;
8066 tsize_t size;
8067{
8068 return (size_t) -1;
8069}
8070
8071
8072static toff_t
8073tiff_seek_in_memory (data, off, whence)
8074 thandle_t data;
8075 toff_t off;
8076 int whence;
8077{
8078 tiff_memory_source *src = (tiff_memory_source *) data;
8079 int idx;
8080
8081 switch (whence)
8082 {
8083 case SEEK_SET: /* Go from beginning of source. */
8084 idx = off;
8085 break;
8086
8087 case SEEK_END: /* Go from end of source. */
8088 idx = src->len + off;
8089 break;
8090
8091 case SEEK_CUR: /* Go from current position. */
8092 idx = src->index + off;
8093 break;
8094
8095 default: /* Invalid `whence'. */
8096 return -1;
8097 }
8098
8099 if (idx > src->len || idx < 0)
8100 return -1;
8101
8102 src->index = idx;
8103 return src->index;
8104}
8105
8106
8107static int
8108tiff_close_memory (data)
8109 thandle_t data;
8110{
8111 /* NOOP */
8112 return 0;
8113}
8114
8115
8116static int
8117tiff_mmap_memory (data, pbase, psize)
8118 thandle_t data;
8119 tdata_t *pbase;
8120 toff_t *psize;
8121{
8122 /* It is already _IN_ memory. */
8123 return 0;
8124}
8125
8126
8127static void
8128tiff_unmap_memory (data, base, size)
8129 thandle_t data;
8130 tdata_t base;
8131 toff_t size;
8132{
8133 /* We don't need to do this. */
8134}
8135
8136
8137static toff_t
8138tiff_size_of_memory (data)
8139 thandle_t data;
8140{
8141 return ((tiff_memory_source *) data)->len;
8142}
8143
8144
8145static void
8146tiff_error_handler (title, format, ap)
8147 const char *title, *format;
8148 va_list ap;
8149{
8150 char buf[512];
8151 int len;
8152
8153 len = sprintf (buf, "TIFF error: %s ", title);
8154 vsprintf (buf + len, format, ap);
8155 add_to_log (buf, Qnil, Qnil);
8156}
8157
8158
8159static void
8160tiff_warning_handler (title, format, ap)
8161 const char *title, *format;
8162 va_list ap;
8163{
8164 char buf[512];
8165 int len;
8166
8167 len = sprintf (buf, "TIFF warning: %s ", title);
8168 vsprintf (buf + len, format, ap);
8169 add_to_log (buf, Qnil, Qnil);
8170}
8171
8172
8173/* Load TIFF image IMG for use on frame F. Value is non-zero if
8174 successful. */
8175
8176static int
8177tiff_load (f, img)
8178 struct frame *f;
8179 struct image *img;
8180{
8181 Lisp_Object file, specified_file;
8182 Lisp_Object specified_data;
8183 TIFF *tiff;
8184 int width, height, x, y;
8185 uint32 *buf;
8186 int rc;
8187 XImagePtr ximg;
8188 struct gcpro gcpro1;
8189 tiff_memory_source memsrc;
8190
8191 specified_file = image_spec_value (img->spec, QCfile, NULL);
8192 specified_data = image_spec_value (img->spec, QCdata, NULL);
8193 file = Qnil;
8194 GCPRO1 (file);
8195
8196 TIFFSetErrorHandler (tiff_error_handler);
8197 TIFFSetWarningHandler (tiff_warning_handler);
8198
8199 if (NILP (specified_data))
8200 {
8201 /* Read from a file */
8202 file = x_find_image_file (specified_file);
8203 if (!STRINGP (file))
8204 {
8205 image_error ("Cannot find image file `%s'", specified_file, Qnil);
8206 UNGCPRO;
8207 return 0;
8208 }
8209
8210 /* Try to open the image file. */
8211 tiff = TIFFOpen (SDATA (file), "r");
8212 if (tiff == NULL)
8213 {
8214 image_error ("Cannot open `%s'", file, Qnil);
8215 UNGCPRO;
8216 return 0;
8217 }
8218 }
8219 else
8220 {
8221 /* Memory source! */
8222 memsrc.bytes = SDATA (specified_data);
8223 memsrc.len = SBYTES (specified_data);
8224 memsrc.index = 0;
8225
8226 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
8227 (TIFFReadWriteProc) tiff_read_from_memory,
8228 (TIFFReadWriteProc) tiff_write_from_memory,
8229 tiff_seek_in_memory,
8230 tiff_close_memory,
8231 tiff_size_of_memory,
8232 tiff_mmap_memory,
8233 tiff_unmap_memory);
8234
8235 if (!tiff)
8236 {
8237 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
8238 UNGCPRO;
8239 return 0;
8240 }
8241 }
8242
8243 /* Get width and height of the image, and allocate a raster buffer
8244 of width x height 32-bit values. */
8245 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
8246 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
8247 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
8248
8249 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
8250 TIFFClose (tiff);
8251 if (!rc)
8252 {
8253 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
8254 xfree (buf);
8255 UNGCPRO;
8256 return 0;
8257 }
8258
8259 /* Create the X image and pixmap. */
8260 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
8261 {
8262 xfree (buf);
8263 UNGCPRO;
8264 return 0;
8265 }
8266
8267#if 0 /* TODO: Color tables. */
8268 /* Initialize the color table. */
8269 init_color_table ();
8270#endif
8271
8272 /* Process the pixel raster. Origin is in the lower-left corner. */
8273 for (y = 0; y < height; ++y)
8274 {
8275 uint32 *row = buf + y * width;
8276
8277 for (x = 0; x < width; ++x)
8278 {
8279 uint32 abgr = row[x];
8280 int r = TIFFGetR (abgr) << 8;
8281 int g = TIFFGetG (abgr) << 8;
8282 int b = TIFFGetB (abgr) << 8;
8283 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
8284 }
8285 }
8286
8287#if 0 /* TODO: Color tables. */
8288 /* Remember the colors allocated for the image. Free the color table. */
8289 img->colors = colors_in_color_table (&img->ncolors);
8290 free_color_table ();
8291#endif
8292
8293 img->width = width;
8294 img->height = height;
8295
8296 /* Maybe fill in the background field while we have ximg handy. */
8297 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
8298 IMAGE_BACKGROUND (img, f, ximg);
8299
8300 /* Put the image into the pixmap, then free the X image and its buffer. */
8301 x_put_x_image (f, ximg, img->pixmap, width, height);
8302 x_destroy_x_image (ximg);
8303 xfree (buf);
8304
8305 UNGCPRO;
8306 return 1;
8307}
8308
8309#endif /* HAVE_TIFF */
8310
8311
8312
8313/***********************************************************************
8314 GIF
8315 ***********************************************************************/
8316
8317static int gif_image_p P_ ((Lisp_Object object));
8318static int gif_load P_ ((struct frame *f, struct image *img));
8319
8320/* The symbol `gif' identifying images of this type. */
8321
8322Lisp_Object Qgif;
8323
8324/* Indices of image specification fields in gif_format, below. */
8325
8326enum gif_keyword_index
8327{
8328 GIF_TYPE,
8329 GIF_DATA,
8330 GIF_FILE,
8331 GIF_ASCENT,
8332 GIF_MARGIN,
8333 GIF_RELIEF,
8334 GIF_ALGORITHM,
8335 GIF_HEURISTIC_MASK,
8336 GIF_MASK,
8337 GIF_IMAGE,
8338 GIF_BACKGROUND,
8339 GIF_LAST
8340};
8341
8342/* Vector of image_keyword structures describing the format
8343 of valid user-defined image specifications. */
8344
8345static struct image_keyword gif_format[GIF_LAST] =
8346{
8347 {":type", IMAGE_SYMBOL_VALUE, 1},
8348 {":data", IMAGE_STRING_VALUE, 0},
8349 {":file", IMAGE_STRING_VALUE, 0},
8350 {":ascent", IMAGE_ASCENT_VALUE, 0},
8351 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
8352 {":relief", IMAGE_INTEGER_VALUE, 0},
8353 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8354 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8355 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8356 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8357 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
8358};
8359
8360/* Structure describing the image type `gif'. */
8361
8362static struct image_type gif_type =
8363{
8364 &Qgif,
8365 gif_image_p,
8366 gif_load,
8367 x_clear_image,
8368 NULL
8369};
8370
8371
8372/* Return non-zero if OBJECT is a valid GIF image specification. */
8373
8374static int
8375gif_image_p (object)
8376 Lisp_Object object;
8377{
8378 struct image_keyword fmt[GIF_LAST];
8379 bcopy (gif_format, fmt, sizeof fmt);
8380
8381 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif))
8382 return 0;
8383
8384 /* Must specify either the :data or :file keyword. */
8385 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
8386}
8387
8388#ifndef HAVE_GIF
8389
8390static int
8391gif_load (f, img)
8392 struct frame *f;
8393 struct image *img;
8394{
8395 Lisp_Object specified_file, file;
8396 Lisp_Object specified_data;
8397 OSErr err;
8398 Boolean graphic_p, movie_p, prefer_graphic_p;
8399 Handle dh = NULL;
8400 Movie movie = NULL;
8401 Lisp_Object image;
8402 Track track = NULL;
8403 Media media = NULL;
8404 long nsamples;
8405 Rect rect;
8406 Lisp_Object specified_bg;
8407 XColor color;
8408 RGBColor bg_color;
8409 int width, height;
8410 XImagePtr ximg;
8411 TimeValue time;
8412 struct gcpro gcpro1;
8413 int ino;
8414
8415 specified_file = image_spec_value (img->spec, QCfile, NULL);
8416 specified_data = image_spec_value (img->spec, QCdata, NULL);
8417
8418 if (NILP (specified_data))
8419 {
8420 /* Read from a file */
8421 FSSpec fss;
8422 short refnum;
8423
8424 err = find_image_fsspec (specified_file, &file, &fss);
8425 if (err != noErr)
8426 {
8427 if (err == fnfErr)
8428 image_error ("Cannot find image file `%s'", specified_file, Qnil);
8429 else
8430 goto open_error;
8431 }
8432
8433 err = CanQuickTimeOpenFile (&fss, kQTFileTypeGIF, 0,
8434 &graphic_p, &movie_p, &prefer_graphic_p, 0);
8435 if (err != noErr)
8436 goto open_error;
8437
8438 if (!graphic_p && !movie_p)
8439 goto open_error;
8440 if (prefer_graphic_p)
8441 return image_load_qt_1 (f, img, kQTFileTypeGIF, &fss, NULL);
8442 err = OpenMovieFile (&fss, &refnum, fsRdPerm);
8443 if (err != noErr)
8444 goto open_error;
8445 err = NewMovieFromFile (&movie, refnum, NULL, NULL, 0, NULL);
8446 CloseMovieFile (refnum);
8447 if (err != noErr)
8448 {
8449 image_error ("Error reading `%s'", file, Qnil);
8450 return 0;
8451 }
8452 }
8453 else
8454 {
8455 /* Memory source! */
8456 Handle dref = NULL;
8457 long file_type_atom[3];
8458
8459 err = PtrToHand (SDATA (specified_data), &dh, SBYTES (specified_data));
8460 if (err != noErr)
8461 {
8462 image_error ("Cannot allocate data handle for `%s'",
8463 img->spec, Qnil);
8464 goto error;
8465 }
8466
8467 file_type_atom[0] = EndianU32_NtoB (sizeof (long) * 3);
8468 file_type_atom[1] = EndianU32_NtoB (kDataRefExtensionMacOSFileType);
8469 file_type_atom[2] = EndianU32_NtoB (kQTFileTypeGIF);
8470 err = PtrToHand (&dh, &dref, sizeof (Handle));
8471 if (err == noErr)
8472 /* no file name */
8473 err = PtrAndHand ("\p", dref, 1);
8474 if (err == noErr)
8475 err = PtrAndHand (file_type_atom, dref, sizeof (long) * 3);
8476 if (err != noErr)
8477 {
8478 image_error ("Cannot allocate handle data ref for `%s'", img->spec, Qnil);
8479 goto error;
8480 }
8481 err = CanQuickTimeOpenDataRef (dref, HandleDataHandlerSubType, &graphic_p,
8482 &movie_p, &prefer_graphic_p, 0);
8483 if (err != noErr)
8484 goto open_error;
8485
8486 if (!graphic_p && !movie_p)
8487 goto open_error;
8488 if (prefer_graphic_p)
8489 {
8490 int success_p;
8491
8492 DisposeHandle (dref);
8493 success_p = image_load_qt_1 (f, img, kQTFileTypeGIF, NULL, dh);
8494 DisposeHandle (dh);
8495 return success_p;
8496 }
8497 err = NewMovieFromDataRef (&movie, 0, NULL, dref,
8498 HandleDataHandlerSubType);
8499 DisposeHandle (dref);
8500 if (err != noErr)
8501 goto open_error;
8502 }
8503
8504 image = image_spec_value (img->spec, QCindex, NULL);
8505 ino = INTEGERP (image) ? XFASTINT (image) : 0;
8506 track = GetMovieIndTrack (movie, 1);
8507 media = GetTrackMedia (track);
8508 nsamples = GetMediaSampleCount (media);
8509 if (ino >= nsamples)
8510 {
8511 image_error ("Invalid image number `%s' in image `%s'",
8512 image, img->spec);
8513 goto error;
8514 }
8515
8516 specified_bg = image_spec_value (img->spec, QCbackground, NULL);
8517 if (!STRINGP (specified_bg) ||
8518 !mac_defined_color (f, SDATA (specified_bg), &color, 0))
8519 {
8520 color.pixel = FRAME_BACKGROUND_PIXEL (f);
8521 color.red = RED16_FROM_ULONG (color.pixel);
8522 color.green = GREEN16_FROM_ULONG (color.pixel);
8523 color.blue = BLUE16_FROM_ULONG (color.pixel);
8524 }
8525 GetMovieBox (movie, &rect);
8526 width = img->width = rect.right - rect.left;
8527 height = img->height = rect.bottom - rect.top;
8528 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
8529 goto error;
8530
8531 SetGWorld (ximg, NULL);
8532 bg_color.red = color.red;
8533 bg_color.green = color.green;
8534 bg_color.blue = color.blue;
8535 RGBBackColor (&bg_color);
8536 SetMovieActive (movie, TRUE);
8537 SetMovieGWorld (movie, ximg, NULL);
8538 SampleNumToMediaTime (media, ino + 1, &time, NULL);
8539 SetMovieTimeValue (movie, time);
8540 MoviesTask (movie, 0L);
8541 DisposeTrackMedia (media);
8542 DisposeMovieTrack (track);
8543 DisposeMovie (movie);
8544 if (dh)
8545 DisposeHandle (dh);
8546 /* Maybe fill in the background field while we have ximg handy. */
8547 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
8548 IMAGE_BACKGROUND (img, f, ximg);
8549
8550 /* Put the image into the pixmap. */
8551 x_put_x_image (f, ximg, img->pixmap, width, height);
8552 x_destroy_x_image (ximg);
8553 return 1;
8554
8555 open_error:
8556 image_error ("Cannot open `%s'", file, Qnil);
8557 error:
8558 if (media)
8559 DisposeTrackMedia (media);
8560 if (track)
8561 DisposeMovieTrack (track);
8562 if (movie)
8563 DisposeMovie (movie);
8564 if (dh)
8565 DisposeHandle (dh);
8566 return 0;
8567}
8568
8569#else
8570
8571#define DrawText gif_DrawText /* avoid conflict with QuickdrawText.h */
8572#include <gif_lib.h>
8573#undef DrawText
8574
8575/* Reading a GIF image from memory
8576 Based on the PNG memory stuff to a certain extent. */
8577
8578typedef struct
8579{
8580 unsigned char *bytes;
8581 size_t len;
8582 int index;
8583}
8584gif_memory_source;
8585
8586
8587/* Make the current memory source available to gif_read_from_memory.
8588 It's done this way because not all versions of libungif support
8589 a UserData field in the GifFileType structure. */
8590static gif_memory_source *current_gif_memory_src;
8591
8592static int
8593gif_read_from_memory (file, buf, len)
8594 GifFileType *file;
8595 GifByteType *buf;
8596 int len;
8597{
8598 gif_memory_source *src = current_gif_memory_src;
8599
8600 if (len > src->len - src->index)
8601 return -1;
8602
8603 bcopy (src->bytes + src->index, buf, len);
8604 src->index += len;
8605 return len;
8606}
8607
8608
8609/* Load GIF image IMG for use on frame F. Value is non-zero if
8610 successful. */
8611
8612static int
8613gif_load (f, img)
8614 struct frame *f;
8615 struct image *img;
8616{
8617 Lisp_Object file, specified_file;
8618 Lisp_Object specified_data;
8619 int rc, width, height, x, y, i;
8620 XImagePtr ximg;
8621 ColorMapObject *gif_color_map;
8622 unsigned long pixel_colors[256];
8623 GifFileType *gif;
8624 struct gcpro gcpro1;
8625 Lisp_Object image;
8626 int ino, image_left, image_top, image_width, image_height;
8627 gif_memory_source memsrc;
8628 unsigned char *raster;
8629
8630 specified_file = image_spec_value (img->spec, QCfile, NULL);
8631 specified_data = image_spec_value (img->spec, QCdata, NULL);
8632 file = Qnil;
8633 GCPRO1 (file);
8634
8635 if (NILP (specified_data))
8636 {
8637 file = x_find_image_file (specified_file);
8638 if (!STRINGP (file))
8639 {
8640 image_error ("Cannot find image file `%s'", specified_file, Qnil);
8641 UNGCPRO;
8642 return 0;
8643 }
8644
8645 /* Open the GIF file. */
8646 gif = DGifOpenFileName (SDATA (file));
8647 if (gif == NULL)
8648 {
8649 image_error ("Cannot open `%s'", file, Qnil);
8650 UNGCPRO;
8651 return 0;
8652 }
8653 }
8654 else
8655 {
8656 /* Read from memory! */
8657 current_gif_memory_src = &memsrc;
8658 memsrc.bytes = SDATA (specified_data);
8659 memsrc.len = SBYTES (specified_data);
8660 memsrc.index = 0;
8661
8662 gif = DGifOpen (&memsrc, gif_read_from_memory);
8663 if (!gif)
8664 {
8665 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
8666 UNGCPRO;
8667 return 0;
8668 }
8669 }
8670
8671 /* Read entire contents. */
8672 rc = DGifSlurp (gif);
8673 if (rc == GIF_ERROR)
8674 {
8675 image_error ("Error reading `%s'", img->spec, Qnil);
8676 DGifCloseFile (gif);
8677 UNGCPRO;
8678 return 0;
8679 }
8680
8681 image = image_spec_value (img->spec, QCindex, NULL);
8682 ino = INTEGERP (image) ? XFASTINT (image) : 0;
8683 if (ino >= gif->ImageCount)
8684 {
8685 image_error ("Invalid image number `%s' in image `%s'",
8686 image, img->spec);
8687 DGifCloseFile (gif);
8688 UNGCPRO;
8689 return 0;
8690 }
8691
8692 width = img->width = max (gif->SWidth, gif->Image.Left + gif->Image.Width);
8693 height = img->height = max (gif->SHeight, gif->Image.Top + gif->Image.Height);
8694
8695 /* Create the X image and pixmap. */
8696 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
8697 {
8698 DGifCloseFile (gif);
8699 UNGCPRO;
8700 return 0;
8701 }
8702
8703 /* Allocate colors. */
8704 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
8705 if (!gif_color_map)
8706 gif_color_map = gif->SColorMap;
8707#if 0 /* TODO: Color tables */
8708 init_color_table ();
8709#endif
8710 bzero (pixel_colors, sizeof pixel_colors);
8711
8712 for (i = 0; i < gif_color_map->ColorCount; ++i)
8713 {
8714 int r = gif_color_map->Colors[i].Red << 8;
8715 int g = gif_color_map->Colors[i].Green << 8;
8716 int b = gif_color_map->Colors[i].Blue << 8;
8717 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
8718 }
8719
8720#if 0 /* TODO: Color tables */
8721 img->colors = colors_in_color_table (&img->ncolors);
8722 free_color_table ();
8723#endif
8724
8725 /* Clear the part of the screen image that are not covered by
8726 the image from the GIF file. Full animated GIF support
8727 requires more than can be done here (see the gif89 spec,
8728 disposal methods). Let's simply assume that the part
8729 not covered by a sub-image is in the frame's background color. */
8730 image_top = gif->SavedImages[ino].ImageDesc.Top;
8731 image_left = gif->SavedImages[ino].ImageDesc.Left;
8732 image_width = gif->SavedImages[ino].ImageDesc.Width;
8733 image_height = gif->SavedImages[ino].ImageDesc.Height;
8734
8735 for (y = 0; y < image_top; ++y)
8736 for (x = 0; x < width; ++x)
8737 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
8738
8739 for (y = image_top + image_height; y < height; ++y)
8740 for (x = 0; x < width; ++x)
8741 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
8742
8743 for (y = image_top; y < image_top + image_height; ++y)
8744 {
8745 for (x = 0; x < image_left; ++x)
8746 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
8747 for (x = image_left + image_width; x < width; ++x)
8748 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
8749 }
8750
8751 /* Read the GIF image into the X image. We use a local variable
8752 `raster' here because RasterBits below is a char *, and invites
8753 problems with bytes >= 0x80. */
8754 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
8755
8756 if (gif->SavedImages[ino].ImageDesc.Interlace)
8757 {
8758 static int interlace_start[] = {0, 4, 2, 1};
8759 static int interlace_increment[] = {8, 8, 4, 2};
8760 int pass;
8761 int row = interlace_start[0];
8762
8763 pass = 0;
8764
8765 for (y = 0; y < image_height; y++)
8766 {
8767 if (row >= image_height)
8768 {
8769 row = interlace_start[++pass];
8770 while (row >= image_height)
8771 row = interlace_start[++pass];
8772 }
8773
8774 for (x = 0; x < image_width; x++)
8775 {
8776 int i = raster[(y * image_width) + x];
8777 XPutPixel (ximg, x + image_left, row + image_top,
8778 pixel_colors[i]);
8779 }
8780
8781 row += interlace_increment[pass];
8782 }
8783 }
8784 else
8785 {
8786 for (y = 0; y < image_height; ++y)
8787 for (x = 0; x < image_width; ++x)
8788 {
8789 int i = raster[y * image_width + x];
8790 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
8791 }
8792 }
8793
8794 DGifCloseFile (gif);
8795
8796 /* Maybe fill in the background field while we have ximg handy. */
8797 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
8798 IMAGE_BACKGROUND (img, f, ximg);
8799
8800 /* Put the image into the pixmap, then free the X image and its buffer. */
8801 x_put_x_image (f, ximg, img->pixmap, width, height);
8802 x_destroy_x_image (ximg);
8803
8804 UNGCPRO;
8805 return 1;
8806}
8807#endif /* HAVE_GIF */
8808
8809
8810
8811/***********************************************************************
8812 Ghostscript
8813 ***********************************************************************/
8814
8815/* The symbol `postscript' identifying images of this type. */
8816
8817Lisp_Object Qpostscript;
8818
8819/* Keyword symbols. */
8820
8821Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
8822
8823#ifdef HAVE_GHOSTSCRIPT
8824static int gs_image_p P_ ((Lisp_Object object));
8825static int gs_load P_ ((struct frame *f, struct image *img));
8826static void gs_clear_image P_ ((struct frame *f, struct image *img));
8827
8828/* Indices of image specification fields in gs_format, below. */
8829
8830enum gs_keyword_index
8831{
8832 GS_TYPE,
8833 GS_PT_WIDTH,
8834 GS_PT_HEIGHT,
8835 GS_FILE,
8836 GS_LOADER,
8837 GS_BOUNDING_BOX,
8838 GS_ASCENT,
8839 GS_MARGIN,
8840 GS_RELIEF,
8841 GS_ALGORITHM,
8842 GS_HEURISTIC_MASK,
8843 GS_MASK,
8844 GS_BACKGROUND,
8845 GS_LAST
8846};
8847
8848/* Vector of image_keyword structures describing the format
8849 of valid user-defined image specifications. */
8850
8851static struct image_keyword gs_format[GS_LAST] =
8852{
8853 {":type", IMAGE_SYMBOL_VALUE, 1},
8854 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
8855 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
8856 {":file", IMAGE_STRING_VALUE, 1},
8857 {":loader", IMAGE_FUNCTION_VALUE, 0},
8858 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
8859 {":ascent", IMAGE_ASCENT_VALUE, 0},
8860 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
8861 {":relief", IMAGE_INTEGER_VALUE, 0},
8862 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8863 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8864 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8865 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
8866};
8867
8868/* Structure describing the image type `ghostscript'. */
8869
8870static struct image_type gs_type =
8871{
8872 &Qpostscript,
8873 gs_image_p,
8874 gs_load,
8875 gs_clear_image,
8876 NULL
8877};
8878
8879
8880/* Free X resources of Ghostscript image IMG which is used on frame F. */
8881
8882static void
8883gs_clear_image (f, img)
8884 struct frame *f;
8885 struct image *img;
8886{
8887 /* IMG->data.ptr_val may contain a recorded colormap. */
8888 xfree (img->data.ptr_val);
8889 x_clear_image (f, img);
8890}
8891
8892
8893/* Return non-zero if OBJECT is a valid Ghostscript image
8894 specification. */
8895
8896static int
8897gs_image_p (object)
8898 Lisp_Object object;
8899{
8900 struct image_keyword fmt[GS_LAST];
8901 Lisp_Object tem;
8902 int i;
8903
8904 bcopy (gs_format, fmt, sizeof fmt);
8905
8906 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript))
8907 return 0;
8908
8909 /* Bounding box must be a list or vector containing 4 integers. */
8910 tem = fmt[GS_BOUNDING_BOX].value;
8911 if (CONSP (tem))
8912 {
8913 for (i = 0; i < 4; ++i, tem = XCDR (tem))
8914 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
8915 return 0;
8916 if (!NILP (tem))
8917 return 0;
8918 }
8919 else if (VECTORP (tem))
8920 {
8921 if (XVECTOR (tem)->size != 4)
8922 return 0;
8923 for (i = 0; i < 4; ++i)
8924 if (!INTEGERP (XVECTOR (tem)->contents[i]))
8925 return 0;
8926 }
8927 else
8928 return 0;
8929
8930 return 1;
8931}
8932
8933
8934/* Load Ghostscript image IMG for use on frame F. Value is non-zero
8935 if successful. */
8936
8937static int
8938gs_load (f, img)
8939 struct frame *f;
8940 struct image *img;
8941{
8942 char buffer[100];
8943 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
8944 struct gcpro gcpro1, gcpro2;
8945 Lisp_Object frame;
8946 double in_width, in_height;
8947 Lisp_Object pixel_colors = Qnil;
8948
8949 /* Compute pixel size of pixmap needed from the given size in the
8950 image specification. Sizes in the specification are in pt. 1 pt
8951 = 1/72 in, xdpi and ydpi are stored in the frame's X display
8952 info. */
8953 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
8954 in_width = XFASTINT (pt_width) / 72.0;
8955 img->width = in_width * FRAME_MAC_DISPLAY_INFO (f)->resx;
8956 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
8957 in_height = XFASTINT (pt_height) / 72.0;
8958 img->height = in_height * FRAME_MAC_DISPLAY_INFO (f)->resy;
8959
8960 /* Create the pixmap. */
8961 xassert (img->pixmap == NULL);
8962 img->pixmap = XCreatePixmap (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
8963 img->width, img->height,
8964 one_mac_display_info.n_planes);
8965
8966 if (!img->pixmap)
8967 {
8968 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
8969 return 0;
8970 }
8971
8972 /* Call the loader to fill the pixmap. It returns a process object
8973 if successful. We do not record_unwind_protect here because
8974 other places in redisplay like calling window scroll functions
8975 don't either. Let the Lisp loader use `unwind-protect' instead. */
8976 GCPRO2 (window_and_pixmap_id, pixel_colors);
8977
8978 sprintf (buffer, "%lu %lu",
8979 (unsigned long) FRAME_MAC_WINDOW (f),
8980 (unsigned long) img->pixmap);
8981 window_and_pixmap_id = build_string (buffer);
8982
8983 sprintf (buffer, "%lu %lu",
8984 FRAME_FOREGROUND_PIXEL (f),
8985 FRAME_BACKGROUND_PIXEL (f));
8986 pixel_colors = build_string (buffer);
8987
8988 XSETFRAME (frame, f);
8989 loader = image_spec_value (img->spec, QCloader, NULL);
8990 if (NILP (loader))
8991 loader = intern ("gs-load-image");
8992
8993 img->data.lisp_val = call6 (loader, frame, img->spec,
8994 make_number (img->width),
8995 make_number (img->height),
8996 window_and_pixmap_id,
8997 pixel_colors);
8998 UNGCPRO;
8999 return PROCESSP (img->data.lisp_val);
9000}
9001
9002
9003/* Kill the Ghostscript process that was started to fill PIXMAP on
9004 frame F. Called from XTread_socket when receiving an event
9005 telling Emacs that Ghostscript has finished drawing. */
9006
9007void
9008x_kill_gs_process (pixmap, f)
9009 Pixmap pixmap;
9010 struct frame *f;
9011{
9012 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9013 int class, i;
9014 struct image *img;
9015
9016 /* Find the image containing PIXMAP. */
9017 for (i = 0; i < c->used; ++i)
9018 if (c->images[i]->pixmap == pixmap)
9019 break;
9020
9021 /* Should someone in between have cleared the image cache, for
9022 instance, give up. */
9023 if (i == c->used)
9024 return;
9025
9026 /* Kill the GS process. We should have found PIXMAP in the image
9027 cache and its image should contain a process object. */
9028 img = c->images[i];
9029 xassert (PROCESSP (img->data.lisp_val));
9030 Fkill_process (img->data.lisp_val, Qnil);
9031 img->data.lisp_val = Qnil;
9032
9033#if 0
9034 /* On displays with a mutable colormap, figure out the colors
9035 allocated for the image by looking at the pixels of an XImage for
9036 img->pixmap. */
9037 class = FRAME_MAC_DISPLAY_INFO (f)->visual->class;
9038 if (class != StaticColor && class != StaticGray && class != TrueColor)
9039 {
9040 XImagePtr ximg;
9041
9042 BLOCK_INPUT;
9043
9044 /* Try to get an XImage for img->pixmep. */
9045 ximg = XGetImage (FRAME_MAC_DISPLAY (f), img->pixmap,
9046 0, 0, img->width, img->height, ~0, ZPixmap);
9047 if (ximg)
9048 {
9049 int x, y;
9050
9051 /* Initialize the color table. */
9052 init_color_table ();
9053
9054 /* For each pixel of the image, look its color up in the
9055 color table. After having done so, the color table will
9056 contain an entry for each color used by the image. */
9057 for (y = 0; y < img->height; ++y)
9058 for (x = 0; x < img->width; ++x)
9059 {
9060 unsigned long pixel = XGetPixel (ximg, x, y);
9061 lookup_pixel_color (f, pixel);
9062 }
9063
9064 /* Record colors in the image. Free color table and XImage. */
9065 img->colors = colors_in_color_table (&img->ncolors);
9066 free_color_table ();
9067 XDestroyImage (ximg);
9068
9069#if 0 /* This doesn't seem to be the case. If we free the colors
9070 here, we get a BadAccess later in x_clear_image when
9071 freeing the colors. */
9072 /* We have allocated colors once, but Ghostscript has also
9073 allocated colors on behalf of us. So, to get the
9074 reference counts right, free them once. */
9075 if (img->ncolors)
9076 x_free_colors (f, img->colors, img->ncolors);
9077#endif
9078 }
9079 else
9080 image_error ("Cannot get X image of `%s'; colors will not be freed",
9081 img->spec, Qnil);
9082
9083 UNBLOCK_INPUT;
9084 }
9085#endif
9086
9087 /* Now that we have the pixmap, compute mask and transform the
9088 image if requested. */
9089 BLOCK_INPUT;
9090 postprocess_image (f, img);
9091 UNBLOCK_INPUT;
9092}
9093
9094#endif /* HAVE_GHOSTSCRIPT */
9095
9096 3305
9097/*********************************************************************** 3306/***********************************************************************
9098 Window properties 3307 Window properties
@@ -10001,38 +4210,6 @@ selection dialog's entry field, if MUSTMATCH is non-nil. */)
10001 4210
10002 4211
10003/*********************************************************************** 4212/***********************************************************************
10004 Tests
10005 ***********************************************************************/
10006
10007#if GLYPH_DEBUG
10008
10009DEFUN ("imagep", Fimagep, Simagep, 1, 1, 0,
10010 doc: /* Value is non-nil if SPEC is a valid image specification. */)
10011 (spec)
10012 Lisp_Object spec;
10013{
10014 return valid_image_p (spec) ? Qt : Qnil;
10015}
10016
10017
10018DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0, "")
10019 (spec)
10020 Lisp_Object spec;
10021{
10022 int id = -1;
10023
10024 if (valid_image_p (spec))
10025 id = lookup_image (SELECTED_FRAME (), spec);
10026
10027 debug_print (spec);
10028 return make_number (id);
10029}
10030
10031#endif /* GLYPH_DEBUG != 0 */
10032
10033
10034
10035/***********************************************************************
10036 Initialization 4213 Initialization
10037 ***********************************************************************/ 4214 ***********************************************************************/
10038 4215
@@ -10087,8 +4264,6 @@ syms_of_macfns ()
10087 staticpro (&Qsuppress_icon); 4264 staticpro (&Qsuppress_icon);
10088 Qundefined_color = intern ("undefined-color"); 4265 Qundefined_color = intern ("undefined-color");
10089 staticpro (&Qundefined_color); 4266 staticpro (&Qundefined_color);
10090 Qcenter = intern ("center");
10091 staticpro (&Qcenter);
10092 /* This is the end of symbol initialization. */ 4267 /* This is the end of symbol initialization. */
10093 4268
10094 Qhyper = intern ("hyper"); 4269 Qhyper = intern ("hyper");
@@ -10110,22 +4285,6 @@ syms_of_macfns ()
10110 Vtext_property_default_nonsticky 4285 Vtext_property_default_nonsticky
10111 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky); 4286 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
10112 4287
10113
10114 Qlaplace = intern ("laplace");
10115 staticpro (&Qlaplace);
10116 Qemboss = intern ("emboss");
10117 staticpro (&Qemboss);
10118 Qedge_detection = intern ("edge-detection");
10119 staticpro (&Qedge_detection);
10120 Qheuristic = intern ("heuristic");
10121 staticpro (&Qheuristic);
10122 QCmatrix = intern (":matrix");
10123 staticpro (&QCmatrix);
10124 QCcolor_adjustment = intern (":color-adjustment");
10125 staticpro (&QCcolor_adjustment);
10126 QCmask = intern (":mask");
10127 staticpro (&QCmask);
10128
10129 Qface_set_after_frame_default = intern ("face-set-after-frame-default"); 4288 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
10130 staticpro (&Qface_set_after_frame_default); 4289 staticpro (&Qface_set_after_frame_default);
10131 4290
@@ -10134,16 +4293,6 @@ syms_of_macfns ()
10134 Fput (Qundefined_color, Qerror_message, 4293 Fput (Qundefined_color, Qerror_message,
10135 build_string ("Undefined color")); 4294 build_string ("Undefined color"));
10136 4295
10137 DEFVAR_BOOL ("cross-disabled-images", &cross_disabled_images,
10138 doc: /* Non-nil means always draw a cross over disabled images.
10139Disabled images are those having an `:conversion disabled' property.
10140A cross is always drawn on black & white displays. */);
10141 cross_disabled_images = 0;
10142
10143 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
10144 doc: /* List of directories to search for window system bitmap files. */);
10145 Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH");
10146
10147 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape, 4296 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
10148 doc: /* The shape of the pointer when over text. 4297 doc: /* The shape of the pointer when over text.
10149Changing the value does not affect existing frames 4298Changing the value does not affect existing frames
@@ -10198,13 +4347,6 @@ such a font. This is especially effective for such large fonts as
10198Chinese, Japanese, and Korean. */); 4347Chinese, Japanese, and Korean. */);
10199 Vx_pixel_size_width_font_regexp = Qnil; 4348 Vx_pixel_size_width_font_regexp = Qnil;
10200 4349
10201 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
10202 doc: /* Time after which cached images are removed from the cache.
10203When an image has not been displayed this many seconds, remove it
10204from the image cache. Value must be an integer or nil with nil
10205meaning don't clear the cache. */);
10206 Vimage_cache_eviction_delay = make_number (30 * 60);
10207
10208 /* X window properties. */ 4350 /* X window properties. */
10209 defsubr (&Sx_change_window_property); 4351 defsubr (&Sx_change_window_property);
10210 defsubr (&Sx_delete_window_property); 4352 defsubr (&Sx_delete_window_property);
@@ -10249,41 +4391,6 @@ meaning don't clear the cache. */);
10249 set_frame_fontset_func = x_set_font; 4391 set_frame_fontset_func = x_set_font;
10250 check_window_system_func = check_mac; 4392 check_window_system_func = check_mac;
10251 4393
10252 /* Images. */
10253 Qxbm = intern ("xbm");
10254 staticpro (&Qxbm);
10255 QCconversion = intern (":conversion");
10256 staticpro (&QCconversion);
10257 QCheuristic_mask = intern (":heuristic-mask");
10258 staticpro (&QCheuristic_mask);
10259 QCcolor_symbols = intern (":color-symbols");
10260 staticpro (&QCcolor_symbols);
10261 QCascent = intern (":ascent");
10262 staticpro (&QCascent);
10263 QCmargin = intern (":margin");
10264 staticpro (&QCmargin);
10265 QCrelief = intern (":relief");
10266 staticpro (&QCrelief);
10267 Qpostscript = intern ("postscript");
10268 staticpro (&Qpostscript);
10269 QCloader = intern (":loader");
10270 staticpro (&QCloader);
10271 QCbounding_box = intern (":bounding-box");
10272 staticpro (&QCbounding_box);
10273 QCpt_width = intern (":pt-width");
10274 staticpro (&QCpt_width);
10275 QCpt_height = intern (":pt-height");
10276 staticpro (&QCpt_height);
10277 QCindex = intern (":index");
10278 staticpro (&QCindex);
10279 Qpbm = intern ("pbm");
10280 staticpro (&Qpbm);
10281
10282#if HAVE_XPM
10283 Qxpm = intern ("xpm");
10284 staticpro (&Qxpm);
10285#endif
10286
10287 Qjpeg = intern ("jpeg"); 4394 Qjpeg = intern ("jpeg");
10288 staticpro (&Qjpeg); 4395 staticpro (&Qjpeg);
10289 4396
@@ -10300,11 +4407,6 @@ meaning don't clear the cache. */);
10300 defsubr (&Simage_size); 4407 defsubr (&Simage_size);
10301 defsubr (&Simage_mask_p); 4408 defsubr (&Simage_mask_p);
10302 4409
10303#if GLYPH_DEBUG
10304 defsubr (&Simagep);
10305 defsubr (&Slookup_image);
10306#endif
10307
10308 hourglass_atimer = NULL; 4410 hourglass_atimer = NULL;
10309 hourglass_shown_p = 0; 4411 hourglass_shown_p = 0;
10310 4412
@@ -10320,35 +4422,5 @@ meaning don't clear the cache. */);
10320#endif 4422#endif
10321} 4423}
10322 4424
10323
10324void
10325init_xfns ()
10326{
10327 image_types = NULL;
10328 Vimage_types = Qnil;
10329
10330 define_image_type (&xbm_type);
10331#if HAVE_GHOSTSCRIPT
10332 define_image_type (&gs_type);
10333#endif
10334 define_image_type (&pbm_type);
10335
10336#if HAVE_XPM
10337 define_image_type (&xpm_type);
10338#endif
10339
10340 define_image_type (&jpeg_type);
10341 define_image_type (&tiff_type);
10342 define_image_type (&gif_type);
10343 define_image_type (&png_type);
10344
10345 /* Animated gifs use QuickTime Movie Toolbox. So initialize it
10346 here. */
10347 EnterMovies ();
10348#ifdef MAC_OSX
10349 init_image_func_pointer ();
10350#endif
10351}
10352
10353/* arch-tag: d7591289-f374-4377-b245-12f5dbbb8edc 4425/* arch-tag: d7591289-f374-4377-b245-12f5dbbb8edc
10354 (do not change this comment) */ 4426 (do not change this comment) */