image.c 238 KB
Newer Older
1
/* Functions for image support on window system.
2 3

Copyright (C) 1989, 1992-2012 Free Software Foundation, Inc.
4 5 6

This file is part of GNU Emacs.

7
GNU Emacs is free software: you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9 10
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
11 12 13 14 15 16 17

GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
18
along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
19 20 21 22 23

#include <config.h>
#include <stdio.h>
#include <unistd.h>

24 25 26 27 28 29
#ifdef HAVE_PNG
#if defined HAVE_LIBPNG_PNG_H
# include <libpng/png.h>
#else
# include <png.h>
#endif
30
#endif
31

32 33
#include <setjmp.h>

34 35
#include <c-ctype.h>

36 37 38 39 40 41 42 43 44 45 46
/* This makes the fields of a Display accessible, in Xlib header files.  */

#define XLIB_ILLEGAL_ACCESS

#include "lisp.h"
#include "frame.h"
#include "window.h"
#include "dispextern.h"
#include "blockinput.h"
#include "systime.h"
#include <epaths.h>
47
#include "character.h"
48
#include "coding.h"
49
#include "termhooks.h"
50
#include "font.h"
51

52
#ifdef HAVE_SYS_STAT_H
53
#include <sys/stat.h>
54 55 56 57 58 59 60 61 62
#endif /* HAVE_SYS_STAT_H */

#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif /* HAVE_SYS_TYPES_H */

#ifdef HAVE_WINDOW_SYSTEM
#include TERM_HEADER
#endif /* HAVE_WINDOW_SYSTEM */
63

64
#ifdef HAVE_X_WINDOWS
65 66 67
#define COLOR_TABLE_SUPPORT 1

typedef struct x_bitmap_record Bitmap_Record;
Juanma Barranquero's avatar
Juanma Barranquero committed
68
#define GET_PIXEL(ximg, x, y) XGetPixel (ximg, x, y)
69 70 71 72
#define NO_PIXMAP None

#define RGB_PIXEL_COLOR unsigned long

73 74
#define PIX_MASK_RETAIN	0
#define PIX_MASK_DRAW	1
75 76 77
#endif /* HAVE_X_WINDOWS */

#ifdef HAVE_NTGUI
78 79 80

/* We need (or want) w32.h only when we're _not_ compiling for Cygwin.  */
#ifdef WINDOWSNT
Daniel Colascione's avatar
Daniel Colascione committed
81
# include "w32.h"
82 83
#endif

84 85 86 87
/* W32_TODO : Color tables on W32.  */
#undef COLOR_TABLE_SUPPORT

typedef struct w32_bitmap_record Bitmap_Record;
Juanma Barranquero's avatar
Juanma Barranquero committed
88
#define GET_PIXEL(ximg, x, y) GetPixel (ximg, x, y)
89 90 91 92
#define NO_PIXMAP 0

#define RGB_PIXEL_COLOR COLORREF

93 94
#define PIX_MASK_RETAIN	0
#define PIX_MASK_DRAW	1
95 96 97

#define x_defined_color w32_defined_color
#define DefaultDepthOfScreen(screen) (one_w32_display_info.n_cbits)
98

99 100 101 102
/* Version of libpng that we were compiled with, or -1 if no PNG
   support was compiled in.  This is tested by w32-win.el to correctly
   set up the alist used to search for PNG libraries.  */
Lisp_Object Qlibpng_version;
103 104
#endif /* HAVE_NTGUI */

105 106 107 108 109
#ifdef HAVE_NS
#undef COLOR_TABLE_SUPPORT

typedef struct ns_bitmap_record Bitmap_Record;

Juanma Barranquero's avatar
Juanma Barranquero committed
110
#define GET_PIXEL(ximg, x, y) XGetPixel (ximg, x, y)
111 112 113 114 115 116 117 118 119 120
#define NO_PIXMAP 0

#define RGB_PIXEL_COLOR unsigned long
#define ZPixmap 0

#define PIX_MASK_RETAIN	0
#define PIX_MASK_DRAW	1

#define x_defined_color(f, name, color_def, alloc) \
  ns_defined_color (f, name, color_def, alloc, 0)
121
#define DefaultDepthOfScreen(screen) x_display_list->n_planes
122 123 124
#endif /* HAVE_NS */


125 126
/* The symbol `postscript' identifying images of this type.  */

127
static Lisp_Object Qpostscript;
128

129 130 131
static void x_disable_image (struct frame *, struct image *);
static void x_edge_detection (struct frame *, struct image *, Lisp_Object,
                              Lisp_Object);
132

133 134
static void init_color_table (void);
static unsigned long lookup_rgb_color (struct frame *f, int r, int g, int b);
135
#ifdef COLOR_TABLE_SUPPORT
136 137
static void free_color_table (void);
static unsigned long *colors_in_color_table (int *n);
138 139 140 141 142 143 144 145 146 147 148 149 150
#endif

/* Code to deal with bitmaps.  Bitmaps are referenced by their bitmap
   id, which is just an int that this section returns.  Bitmaps are
   reference counted so they can be shared among frames.

   Bitmap indices are guaranteed to be > 0, so a negative number can
   be used to indicate no bitmap.

   If you use x_create_bitmap_from_data, then you must keep track of
   the bitmaps yourself.  That is, creating a bitmap from the same
   data more than once will not be caught.  */

151 152 153 154 155 156
#ifdef HAVE_NS
XImagePtr
XGetImage (Display *display, Pixmap pixmap, int x, int y,
           unsigned int width, unsigned int height,
           unsigned long plane_mask, int format)
{
157
  /* TODO: not sure what this function is supposed to do.. */
158
  ns_retain_object (pixmap);
159 160 161 162 163 164 165
  return pixmap;
}

/* use with imgs created by ns_image_for_XPM */
unsigned long
XGetPixel (XImagePtr ximage, int x, int y)
{
166
  return ns_get_pixel (ximage, x, y);
167 168 169 170 171 172 173
}

/* use with imgs created by ns_image_for_XPM; alpha set to 1;
   pixel is assumed to be in form RGB */
void
XPutPixel (XImagePtr ximage, int x, int y, unsigned long pixel)
{
174
  ns_put_pixel (ximage, x, y, pixel);
175 176 177
}
#endif /* HAVE_NS */

178 179 180 181

/* Functions to access the contents of a bitmap, given an id.  */

int
182
x_bitmap_height (FRAME_PTR f, ptrdiff_t id)
183 184 185 186 187
{
  return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].height;
}

int
188
x_bitmap_width (FRAME_PTR f, ptrdiff_t id)
189 190 191 192 193
{
  return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].width;
}

#if defined (HAVE_X_WINDOWS) || defined (HAVE_NTGUI)
194
ptrdiff_t
195
x_bitmap_pixmap (FRAME_PTR f, ptrdiff_t id)
196
{
197
  /* HAVE_NTGUI needs the explicit cast here.  */
198
  return (ptrdiff_t) FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
199 200 201 202 203
}
#endif

#ifdef HAVE_X_WINDOWS
int
204
x_bitmap_mask (FRAME_PTR f, ptrdiff_t id)
205 206 207 208 209 210 211
{
  return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].mask;
}
#endif

/* Allocate a new bitmap record.  Returns index of new record.  */

212
static ptrdiff_t
213
x_allocate_bitmap_record (FRAME_PTR f)
214 215
{
  Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
216
  ptrdiff_t i;
217 218 219 220 221 222 223 224

  if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
    return ++dpyinfo->bitmaps_last;

  for (i = 0; i < dpyinfo->bitmaps_size; ++i)
    if (dpyinfo->bitmaps[i].refcount == 0)
      return i + 1;

Paul Eggert's avatar
Paul Eggert committed
225 226 227
  dpyinfo->bitmaps =
    xpalloc (dpyinfo->bitmaps, &dpyinfo->bitmaps_size,
	     10, -1, sizeof *dpyinfo->bitmaps);
228 229 230 231 232 233
  return ++dpyinfo->bitmaps_last;
}

/* Add one reference to the reference count of the bitmap with id ID.  */

void
234
x_reference_bitmap (FRAME_PTR f, ptrdiff_t id)
235 236 237 238 239 240
{
  ++FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
}

/* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS.  */

241
ptrdiff_t
242
x_create_bitmap_from_data (struct frame *f, char *bits, unsigned int width, unsigned int height)
243 244
{
  Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
245
  ptrdiff_t id;
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264

#ifdef HAVE_X_WINDOWS
  Pixmap bitmap;
  bitmap = XCreateBitmapFromData (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
				  bits, width, height);
  if (! bitmap)
    return -1;
#endif /* HAVE_X_WINDOWS */

#ifdef HAVE_NTGUI
  Pixmap bitmap;
  bitmap = CreateBitmap (width, height,
			 FRAME_X_DISPLAY_INFO (XFRAME (frame))->n_planes,
			 FRAME_X_DISPLAY_INFO (XFRAME (frame))->n_cbits,
			 bits);
  if (! bitmap)
    return -1;
#endif /* HAVE_NTGUI */

265
#ifdef HAVE_NS
266
  void *bitmap = ns_image_from_XBM (bits, width, height);
267 268 269 270
  if (!bitmap)
      return -1;
#endif

271 272
  id = x_allocate_bitmap_record (f);

273 274 275 276 277
#ifdef HAVE_NS
  dpyinfo->bitmaps[id - 1].img = bitmap;
  dpyinfo->bitmaps[id - 1].depth = 1;
#endif

278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
  dpyinfo->bitmaps[id - 1].file = NULL;
  dpyinfo->bitmaps[id - 1].height = height;
  dpyinfo->bitmaps[id - 1].width = width;
  dpyinfo->bitmaps[id - 1].refcount = 1;

#ifdef HAVE_X_WINDOWS
  dpyinfo->bitmaps[id - 1].pixmap = bitmap;
  dpyinfo->bitmaps[id - 1].have_mask = 0;
  dpyinfo->bitmaps[id - 1].depth = 1;
#endif /* HAVE_X_WINDOWS */

#ifdef HAVE_NTGUI
  dpyinfo->bitmaps[id - 1].pixmap = bitmap;
  dpyinfo->bitmaps[id - 1].hinst = NULL;
  dpyinfo->bitmaps[id - 1].depth = 1;
#endif /* HAVE_NTGUI */

  return id;
}

/* Create bitmap from file FILE for frame F.  */

300
ptrdiff_t
301
x_create_bitmap_from_file (struct frame *f, Lisp_Object file)
302
{
303 304
  Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);

305 306 307 308
#ifdef HAVE_NTGUI
  return -1;  /* W32_TODO : bitmap support */
#endif /* HAVE_NTGUI */

309
#ifdef HAVE_NS
310
  ptrdiff_t id;
311
  void *bitmap = ns_image_from_file (file);
312 313 314 315 316 317 318 319

  if (!bitmap)
      return -1;


  id = x_allocate_bitmap_record (f);
  dpyinfo->bitmaps[id - 1].img = bitmap;
  dpyinfo->bitmaps[id - 1].refcount = 1;
Dmitry Antipov's avatar
Dmitry Antipov committed
320
  dpyinfo->bitmaps[id - 1].file = xmalloc (SBYTES (file) + 1);
321
  dpyinfo->bitmaps[id - 1].depth = 1;
322 323
  dpyinfo->bitmaps[id - 1].height = ns_image_width (bitmap);
  dpyinfo->bitmaps[id - 1].width = ns_image_height (bitmap);
324
  strcpy (dpyinfo->bitmaps[id - 1].file, SSDATA (file));
325 326 327
  return id;
#endif

328 329 330
#ifdef HAVE_X_WINDOWS
  unsigned int width, height;
  Pixmap bitmap;
331 332
  int xhot, yhot, result;
  ptrdiff_t id;
333 334 335 336 337 338 339 340 341
  Lisp_Object found;
  int fd;
  char *filename;

  /* Look for an existing bitmap with the same name.  */
  for (id = 0; id < dpyinfo->bitmaps_last; ++id)
    {
      if (dpyinfo->bitmaps[id].refcount
	  && dpyinfo->bitmaps[id].file
342
	  && !strcmp (dpyinfo->bitmaps[id].file, SSDATA (file)))
343 344 345 346 347 348 349 350 351 352 353 354
	{
	  ++dpyinfo->bitmaps[id].refcount;
	  return id + 1;
	}
    }

  /* Search bitmap-file-path for the file, if appropriate.  */
  fd = openp (Vx_bitmap_file_path, file, Qnil, &found, Qnil);
  if (fd < 0)
    return -1;
  emacs_close (fd);

355
  filename = SSDATA (found);
356 357 358 359 360 361 362 363 364 365

  result = XReadBitmapFile (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
			    filename, &width, &height, &bitmap, &xhot, &yhot);
  if (result != BitmapSuccess)
    return -1;

  id = x_allocate_bitmap_record (f);
  dpyinfo->bitmaps[id - 1].pixmap = bitmap;
  dpyinfo->bitmaps[id - 1].have_mask = 0;
  dpyinfo->bitmaps[id - 1].refcount = 1;
Dmitry Antipov's avatar
Dmitry Antipov committed
366
  dpyinfo->bitmaps[id - 1].file = xmalloc (SBYTES (file) + 1);
367 368 369
  dpyinfo->bitmaps[id - 1].depth = 1;
  dpyinfo->bitmaps[id - 1].height = height;
  dpyinfo->bitmaps[id - 1].width = width;
370
  strcpy (dpyinfo->bitmaps[id - 1].file, SSDATA (file));
371 372 373 374 375 376 377 378

  return id;
#endif /* HAVE_X_WINDOWS */
}

/* Free bitmap B.  */

static void
379
free_bitmap_record (Display_Info *dpyinfo, Bitmap_Record *bm)
380 381 382 383 384 385 386 387 388 389 390
{
#ifdef HAVE_X_WINDOWS
  XFreePixmap (dpyinfo->display, bm->pixmap);
  if (bm->have_mask)
    XFreePixmap (dpyinfo->display, bm->mask);
#endif /* HAVE_X_WINDOWS */

#ifdef HAVE_NTGUI
  DeleteObject (bm->pixmap);
#endif /* HAVE_NTGUI */

391
#ifdef HAVE_NS
392
  ns_release_object (bm->img);
393 394
#endif

395 396 397 398 399 400 401 402 403 404
  if (bm->file)
    {
      xfree (bm->file);
      bm->file = NULL;
    }
}

/* Remove reference to bitmap with id number ID.  */

void
405
x_destroy_bitmap (FRAME_PTR f, ptrdiff_t id)
406 407 408 409 410 411 412 413 414
{
  Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);

  if (id > 0)
    {
      Bitmap_Record *bm = &dpyinfo->bitmaps[id - 1];

      if (--bm->refcount == 0)
	{
415
	  block_input ();
416
	  free_bitmap_record (dpyinfo, bm);
417
	  unblock_input ();
418 419 420 421 422 423 424
	}
    }
}

/* Free all the bitmaps for the display specified by DPYINFO.  */

void
425
x_destroy_all_bitmaps (Display_Info *dpyinfo)
426
{
427
  ptrdiff_t i;
428 429 430 431
  Bitmap_Record *bm = dpyinfo->bitmaps;

  for (i = 0; i < dpyinfo->bitmaps_last; i++, bm++)
    if (bm->refcount > 0)
432
      free_bitmap_record (dpyinfo, bm);
433 434 435 436

  dpyinfo->bitmaps_last = 0;
}

437 438 439
static bool x_create_x_image_and_pixmap (struct frame *, int, int, int,
					 XImagePtr *, Pixmap *);
static void x_destroy_x_image (XImagePtr ximg);
440 441 442 443 444 445

#ifdef HAVE_X_WINDOWS

/* Useful functions defined in the section
   `Image type independent image structures' below. */

446 447 448 449
static unsigned long four_corners_best (XImagePtr ximg,
                                        int *corners,
                                        unsigned long width,
                                        unsigned long height);
450 451 452 453 454


/* Create a mask of a bitmap. Note is this not a perfect mask.
   It's nicer with some borders in this context */

455
void
456
x_create_bitmap_mask (struct frame *f, ptrdiff_t id)
457 458 459 460
{
  Pixmap pixmap, mask;
  XImagePtr ximg, mask_img;
  unsigned long width, height;
461
  bool result;
462 463 464 465 466 467 468
  unsigned long bg;
  unsigned long x, y, xp, xm, yp, ym;
  GC gc;

  Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);

  if (!(id > 0))
469
    return;
470 471 472 473 474

  pixmap = x_bitmap_pixmap (f, id);
  width = x_bitmap_width (f, id);
  height = x_bitmap_height (f, id);

475
  block_input ();
476 477 478 479 480
  ximg = XGetImage (FRAME_X_DISPLAY (f), pixmap, 0, 0, width, height,
		    ~0, ZPixmap);

  if (!ximg)
    {
481
      unblock_input ();
482
      return;
483 484 485 486
    }

  result = x_create_x_image_and_pixmap (f, width, height, 1, &mask_img, &mask);

487
  unblock_input ();
488 489 490
  if (!result)
    {
      XDestroyImage (ximg);
491
      return;
492 493
    }

494
  bg = four_corners_best (ximg, NULL, width, height);
495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518

  for (y = 0; y < ximg->height; ++y)
    {
      for (x = 0; x < ximg->width; ++x)
	{
	  xp = x != ximg->width - 1 ? x + 1 : 0;
	  xm = x != 0 ? x - 1 : ximg->width - 1;
	  yp = y != ximg->height - 1 ? y + 1 : 0;
	  ym = y != 0 ? y - 1 : ximg->height - 1;
	  if (XGetPixel (ximg, x, y) == bg
	      && XGetPixel (ximg, x, yp) == bg
	      && XGetPixel (ximg, x, ym) == bg
	      && XGetPixel (ximg, xp, y) == bg
	      && XGetPixel (ximg, xp, yp) == bg
	      && XGetPixel (ximg, xp, ym) == bg
	      && XGetPixel (ximg, xm, y) == bg
	      && XGetPixel (ximg, xm, yp) == bg
	      && XGetPixel (ximg, xm, ym) == bg)
	    XPutPixel (mask_img, x, y, 0);
	  else
	    XPutPixel (mask_img, x, y, 1);
	}
    }

519
  eassert (input_blocked_p ());
520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545
  gc = XCreateGC (FRAME_X_DISPLAY (f), mask, 0, NULL);
  XPutImage (FRAME_X_DISPLAY (f), mask, gc, mask_img, 0, 0, 0, 0,
	     width, height);
  XFreeGC (FRAME_X_DISPLAY (f), gc);

  dpyinfo->bitmaps[id - 1].have_mask = 1;
  dpyinfo->bitmaps[id - 1].mask = mask;

  XDestroyImage (ximg);
  x_destroy_x_image (mask_img);
}

#endif /* HAVE_X_WINDOWS */


/***********************************************************************
			    Image types
 ***********************************************************************/

/* List of supported image types.  Use define_image_type to add new
   types.  Use lookup_image_type to find a type for a given symbol.  */

static struct image_type *image_types;

/* The symbol `xbm' which is used as the type symbol for XBM images.  */

546
static Lisp_Object Qxbm;
547 548 549

/* Keywords.  */

550 551 552 553 554 555
Lisp_Object QCascent, QCmargin, QCrelief;
Lisp_Object QCconversion;
static Lisp_Object QCheuristic_mask;
static Lisp_Object QCcolor_symbols;
static Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask, QCgeometry;
static Lisp_Object QCcrop, QCrotation;
556 557 558

/* Other symbols.  */

559
static Lisp_Object Qcount, Qextension_data, Qdelay;
560
static Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
561

562
/* Forward function prototypes.  */
563

Chong Yidong's avatar
Chong Yidong committed
564
static struct image_type *lookup_image_type (Lisp_Object);
565 566
static void x_laplace (struct frame *, struct image *);
static void x_emboss (struct frame *, struct image *);
567
static void x_build_heuristic_mask (struct frame *, struct image *,
Daniel Colascione's avatar
Daniel Colascione committed
568
                                    Lisp_Object);
Daniel Colascione's avatar
Daniel Colascione committed
569 570
#ifdef WINDOWSNT
extern Lisp_Object Vlibrary_cache;
571
#define CACHE_IMAGE_TYPE(type, status) \
572
  do { Vlibrary_cache = Fcons (Fcons (type, status), Vlibrary_cache); } while (0)
573 574
#else
#define CACHE_IMAGE_TYPE(type, status)
575
#endif
576 577 578

#define ADD_IMAGE_TYPE(type) \
  do { Vimage_types = Fcons (type, Vimage_types); } while (0)
579 580

/* Define a new image type from TYPE.  This adds a copy of TYPE to
581
   image_types and caches the loading status of TYPE.  */
582

Chong Yidong's avatar
Chong Yidong committed
583
static struct image_type *
584
define_image_type (struct image_type *type)
585
{
Chong Yidong's avatar
Chong Yidong committed
586 587
  struct image_type *p = NULL;
  Lisp_Object target_type = *type->type;
588
  bool type_valid = 1;
589

590
  block_input ();
Chong Yidong's avatar
Chong Yidong committed
591 592 593 594 595 596

  for (p = image_types; p; p = p->next)
    if (EQ (*p->type, target_type))
      goto done;

  if (type->init)
597
    {
598
#if defined HAVE_NTGUI && defined WINDOWSNT
Chong Yidong's avatar
Chong Yidong committed
599 600 601 602 603 604 605
      /* If we failed to load the library before, don't try again.  */
      Lisp_Object tested = Fassq (target_type, Vlibrary_cache);
      if (CONSP (tested) && NILP (XCDR (tested)))
	type_valid = 0;
      else
#endif
	{
606
	  type_valid = type->init ();
Chong Yidong's avatar
Chong Yidong committed
607 608 609
	  CACHE_IMAGE_TYPE (target_type, type_valid ? Qt : Qnil);
	}
    }
610

Chong Yidong's avatar
Chong Yidong committed
611
  if (type_valid)
612 613 614
    {
      /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
         The initialized data segment is read-only.  */
615
      p = xmalloc (sizeof *p);
616
      *p = *type;
617 618 619 620
      p->next = image_types;
      image_types = p;
    }

Chong Yidong's avatar
Chong Yidong committed
621
 done:
622
  unblock_input ();
Chong Yidong's avatar
Chong Yidong committed
623
  return p;
624 625 626
}


627
/* Value is true if OBJECT is a valid Lisp image specification.  A
628 629 630 631 632 633
   valid image specification is a list whose car is the symbol
   `image', and whose rest is a property list.  The property list must
   contain a value for key `:type'.  That value must be the name of a
   supported image type.  The rest of the property list depends on the
   image type.  */

634
bool
635
valid_image_p (Lisp_Object object)
636
{
637
  bool valid_p = 0;
638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669

  if (IMAGEP (object))
    {
      Lisp_Object tem;

      for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem))
	if (EQ (XCAR (tem), QCtype))
	  {
	    tem = XCDR (tem);
	    if (CONSP (tem) && SYMBOLP (XCAR (tem)))
	      {
		struct image_type *type;
		type = lookup_image_type (XCAR (tem));
		if (type)
		  valid_p = type->valid_p (object);
	      }

	    break;
	  }
    }

  return valid_p;
}


/* Log error message with format string FORMAT and argument ARG.
   Signaling an error, e.g. when an image cannot be loaded, is not a
   good idea because this would interrupt redisplay, and the error
   message display would lead to another redisplay.  This function
   therefore simply displays a message.  */

static void
670
image_error (const char *format, Lisp_Object arg1, Lisp_Object arg2)
671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687
{
  add_to_log (format, arg1, arg2);
}



/***********************************************************************
			 Image specifications
 ***********************************************************************/

enum image_value_type
{
  IMAGE_DONT_CHECK_VALUE_TYPE,
  IMAGE_STRING_VALUE,
  IMAGE_STRING_OR_NIL_VALUE,
  IMAGE_SYMBOL_VALUE,
  IMAGE_POSITIVE_INTEGER_VALUE,
688
  IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR,
689 690 691 692 693 694 695 696 697 698 699 700 701
  IMAGE_NON_NEGATIVE_INTEGER_VALUE,
  IMAGE_ASCENT_VALUE,
  IMAGE_INTEGER_VALUE,
  IMAGE_FUNCTION_VALUE,
  IMAGE_NUMBER_VALUE,
  IMAGE_BOOL_VALUE
};

/* Structure used when parsing image specifications.  */

struct image_keyword
{
  /* Name of keyword.  */
702
  const char *name;
703 704 705 706

  /* The type of value allowed.  */
  enum image_value_type type;

707 708
  /* True means key must be present.  */
  bool mandatory_p;
709 710 711 712 713 714 715 716 717 718 719 720 721

  /* Used to recognize duplicate keywords in a property list.  */
  int count;

  /* The value that was found.  */
  Lisp_Object value;
};


/* Parse image spec SPEC according to KEYWORDS.  A valid image spec
   has the format (image KEYWORD VALUE ...).  One of the keyword/
   value pairs must be `:type TYPE'.  KEYWORDS is a vector of
   image_keywords structures of size NKEYWORDS describing other
722
   allowed keyword/value pairs.  Value is true if SPEC is valid.  */
723

724
static bool
725 726
parse_image_spec (Lisp_Object spec, struct image_keyword *keywords,
		  int nkeywords, Lisp_Object type)
727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752
{
  int i;
  Lisp_Object plist;

  if (!IMAGEP (spec))
    return 0;

  plist = XCDR (spec);
  while (CONSP (plist))
    {
      Lisp_Object key, value;

      /* First element of a pair must be a symbol.  */
      key = XCAR (plist);
      plist = XCDR (plist);
      if (!SYMBOLP (key))
	return 0;

      /* There must follow a value.  */
      if (!CONSP (plist))
	return 0;
      value = XCAR (plist);
      plist = XCDR (plist);

      /* Find key in KEYWORDS.  Error if not found.  */
      for (i = 0; i < nkeywords; ++i)
753
	if (strcmp (keywords[i].name, SSDATA (SYMBOL_NAME (key))) == 0)
754 755 756 757 758 759 760 761 762 763
	  break;

      if (i == nkeywords)
	continue;

      /* Record that we recognized the keyword.  If a keywords
	 was found more than once, it's an error.  */
      keywords[i].value = value;
      if (keywords[i].count > 1)
	return 0;
764
      ++keywords[i].count;
765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784

      /* Check type of value against allowed type.  */
      switch (keywords[i].type)
	{
	case IMAGE_STRING_VALUE:
	  if (!STRINGP (value))
	    return 0;
	  break;

	case IMAGE_STRING_OR_NIL_VALUE:
	  if (!STRINGP (value) && !NILP (value))
	    return 0;
	  break;

	case IMAGE_SYMBOL_VALUE:
	  if (!SYMBOLP (value))
	    return 0;
	  break;

	case IMAGE_POSITIVE_INTEGER_VALUE:
785
	  if (! RANGED_INTEGERP (1, value, INT_MAX))
786 787 788
	    return 0;
	  break;

789 790
	case IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR:
	  if (RANGED_INTEGERP (0, value, INT_MAX))
791 792
	    break;
	  if (CONSP (value)
793 794
	      && RANGED_INTEGERP (0, XCAR (value), INT_MAX)
	      && RANGED_INTEGERP (0, XCDR (value), INT_MAX))
795 796 797 798 799 800
	    break;
	  return 0;

	case IMAGE_ASCENT_VALUE:
	  if (SYMBOLP (value) && EQ (value, Qcenter))
	    break;
801
	  else if (RANGED_INTEGERP (0, value, 100))
802 803 804 805
	    break;
	  return 0;

	case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
806 807 808
	  /* Unlike the other integer-related cases, this one does not
	     verify that VALUE fits in 'int'.  This is because callers
	     want EMACS_INT.  */
809 810 811 812 813 814 815 816 817
	  if (!INTEGERP (value) || XINT (value) < 0)
	    return 0;
	  break;

	case IMAGE_DONT_CHECK_VALUE_TYPE:
	  break;

	case IMAGE_FUNCTION_VALUE:
	  value = indirect_function (value);
818
	  if (!NILP (Ffunctionp (value)))
819 820 821 822 823 824 825 826 827
	    break;
	  return 0;

	case IMAGE_NUMBER_VALUE:
	  if (!INTEGERP (value) && !FLOATP (value))
	    return 0;
	  break;

	case IMAGE_INTEGER_VALUE:
828
	  if (! TYPE_RANGED_INTEGERP (int, value))
829 830 831 832 833 834 835 836 837
	    return 0;
	  break;

	case IMAGE_BOOL_VALUE:
	  if (!NILP (value) && !EQ (value, Qt))
	    return 0;
	  break;

	default:
838
	  emacs_abort ();
839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855
	  break;
	}

      if (EQ (key, QCtype) && !EQ (type, value))
	return 0;
    }

  /* Check that all mandatory fields are present.  */
  for (i = 0; i < nkeywords; ++i)
    if (keywords[i].mandatory_p && keywords[i].count == 0)
      return 0;

  return NILP (plist);
}


/* Return the value of KEY in image specification SPEC.  Value is nil
856 857
   if KEY is not present in SPEC.  Set *FOUND depending on whether KEY
   was found in SPEC.  */
858 859

static Lisp_Object
860
image_spec_value (Lisp_Object spec, Lisp_Object key, bool *found)
861 862 863
{
  Lisp_Object tail;

864
  eassert (valid_image_p (spec));
865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889

  for (tail = XCDR (spec);
       CONSP (tail) && CONSP (XCDR (tail));
       tail = XCDR (XCDR (tail)))
    {
      if (EQ (XCAR (tail), key))
	{
	  if (found)
	    *found = 1;
	  return XCAR (XCDR (tail));
	}
    }

  if (found)
    *found = 0;
  return Qnil;
}


DEFUN ("image-size", Fimage_size, Simage_size, 1, 3, 0,
       doc: /* Return the size of image SPEC as pair (WIDTH . HEIGHT).
PIXELS non-nil means return the size in pixels, otherwise return the
size in canonical character units.
FRAME is the frame on which the image will be displayed.  FRAME nil
or omitted means use the selected frame.  */)
Dan Nicolaescu's avatar
Dan Nicolaescu committed
890
  (Lisp_Object spec, Lisp_Object pixels, Lisp_Object frame)
891 892 893 894 895 896 897
{
  Lisp_Object size;

  size = Qnil;
  if (valid_image_p (spec))
    {
      struct frame *f = check_x_frame (frame);
898
      ptrdiff_t id = lookup_image (f, spec);
899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919
      struct image *img = IMAGE_FROM_ID (f, id);
      int width = img->width + 2 * img->hmargin;
      int height = img->height + 2 * img->vmargin;

      if (NILP (pixels))
	size = Fcons (make_float ((double) width / FRAME_COLUMN_WIDTH (f)),
		      make_float ((double) height / FRAME_LINE_HEIGHT (f)));
      else
	size = Fcons (make_number (width), make_number (height));
    }
  else
    error ("Invalid image specification");

  return size;
}


DEFUN ("image-mask-p", Fimage_mask_p, Simage_mask_p, 1, 2, 0,
       doc: /* Return t if image SPEC has a mask bitmap.
FRAME is the frame on which the image will be displayed.  FRAME nil
or omitted means use the selected frame.  */)
Dan Nicolaescu's avatar
Dan Nicolaescu committed
920
  (Lisp_Object spec, Lisp_Object frame)
921 922 923 924 925 926 927
{
  Lisp_Object mask;

  mask = Qnil;
  if (valid_image_p (spec))
    {
      struct frame *f = check_x_frame (frame);
928
      ptrdiff_t id = lookup_image (f, spec);
929 930 931 932 933 934 935 936 937 938
      struct image *img = IMAGE_FROM_ID (f, id);
      if (img->mask)
	mask = Qt;
    }
  else
    error ("Invalid image specification");

  return mask;
}

939 940
DEFUN ("image-metadata", Fimage_metadata, Simage_metadata, 1, 2, 0,
       doc: /* Return metadata for image SPEC.
941 942
FRAME is the frame on which the image will be displayed.  FRAME nil
or omitted means use the selected frame.  */)
Dan Nicolaescu's avatar
Dan Nicolaescu committed
943
  (Lisp_Object spec, Lisp_Object frame)
944 945 946 947 948 949 950
{
  Lisp_Object ext;

  ext = Qnil;
  if (valid_image_p (spec))
    {
      struct frame *f = check_x_frame (frame);
951
      ptrdiff_t id = lookup_image (f, spec);
952
      struct image *img = IMAGE_FROM_ID (f, id);
Chong Yidong's avatar
Chong Yidong committed
953
      ext = img->lisp_data;
954 955 956 957 958
    }

  return ext;
}

959 960 961 962 963

/***********************************************************************
		 Image type independent image structures
 ***********************************************************************/

964
#define MAX_IMAGE_SIZE 10.0
965 966 967 968
/* Allocate and return a new image structure for image specification
   SPEC.  SPEC has a hash value of HASH.  */

static struct image *
969
make_image (Lisp_Object spec, EMACS_UINT hash)
970
{
Dmitry Antipov's avatar
Dmitry Antipov committed
971
  struct image *img = xzalloc (sizeof *img);
972
  Lisp_Object file = image_spec_value (spec, QCfile, NULL);
973

974
  eassert (valid_image_p (spec));
975
  img->dependencies = NILP (file) ? Qnil : list1 (file);
976
  img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
977
  eassert (img->type != NULL);
978
  img->spec = spec;
Chong Yidong's avatar
Chong Yidong committed
979
  img->lisp_data = Qnil;
980 981
  img->ascent = DEFAULT_IMAGE_ASCENT;
  img->hash = hash;
982
  img->corners[BOT_CORNER] = -1;  /* Full image */
983 984 985 986 987 988 989
  return img;
}


/* Free image IMG which was used on frame F, including its resources.  */

static void
990
free_image (struct frame *f, struct image *img)
991 992 993
{
  if (img)
    {
994
      struct image_cache *c = FRAME_IMAGE_CACHE (f);
995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012

      /* Remove IMG from the hash table of its cache.  */
      if (img->prev)
	img->prev->next = img->next;
      else
	c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;

      if (img->next)
	img->next->prev = img->prev;

      c->images[img->id] = NULL;

      /* Free resources, then free IMG.  */
      img->type->free (f, img);
      xfree (img);
    }
}

1013
/* Return true if the given widths and heights are valid for display.  */
1014

1015
static bool
1016
check_image_size (struct frame *f, int width, int height)
1017
{
1018
  int w, h;
1019

1020
  if (width <= 0 || height <= 0)
1021 1022
    return 0;

1023
  if (INTEGERP (Vmax_image_size))
1024 1025
    return (width <= XINT (Vmax_image_size)
	    && height <= XINT (Vmax_image_size));
1026 1027
  else if (FLOATP (Vmax_image_size))
    {
1028 1029 1030 1031 1032 1033 1034
      if (f != NULL)
	{
	  w = FRAME_PIXEL_WIDTH (f);
	  h = FRAME_PIXEL_HEIGHT (f);
	}
      else
	w = h = 1024;  /* Arbitrary size for unknown frame. */
1035 1036
      return (width <= XFLOAT_DATA (Vmax_image_size) * w
	      && height <= XFLOAT_DATA (Vmax_image_size) * h);
1037 1038 1039
    }
  else
    return 1;
1040
}
1041 1042 1043 1044 1045

/* Prepare image IMG for display on frame F.  Must be called before
   drawing an image.  */

void
1046
prepare_image_for_display (struct frame *f, struct image *img)
1047 1048
{
  /* We're about to display IMG, so set its timestamp to `now'.  */
1049
  img->timestamp = current_emacs_time ();
1050 1051 1052 1053

  /* If IMG doesn't have a pixmap yet, load it now, using the image
     type dependent loader function.  */
  if (img->pixmap == NO_PIXMAP && !img->load_failed_p)
1054
    img->load_failed_p = ! img->type->load (f, img);
1055

1056 1057 1058 1059 1060 1061 1062
}


/* Value is the number of pixels for the ascent of image IMG when
   drawn in face FACE.  */

int
1063
image_ascent (struct image *img, struct face *face, struct glyph_slice *slice)
1064
{
1065
  int height;
1066 1067
  int ascent;

1068 1069 1070 1071 1072 1073 1074
  if (slice->height == img->height)
    height = img->height + img->vmargin;
  else if (slice->y == 0)
    height = slice->height + img->vmargin;
  else
    height = slice->height;

1075 1076 1077 1078 1079 1080
  if (img->ascent == CENTERED_IMAGE_ASCENT)
    {
      if (face->font)
	{
#ifdef HAVE_NTGUI
	  /* W32 specific version.  Why?. ++kfs  */
1081 1082
	  ascent = height / 2 - (FONT_DESCENT (face->font)
				 - FONT_BASE (face->font)) / 2;
1083 1084 1085 1086 1087 1088
#else
	  /* This expression is arranged so that if the image can't be
	     exactly centered, it will be moved slightly up.  This is
	     because a typical font is `top-heavy' (due to the presence
	     uppercase letters), so the image placement should err towards
	     being top-heavy too.  It also just generally looks better.  */
Juanma Barranquero's avatar
Juanma Barranquero committed
1089 1090
	  ascent = (height + FONT_BASE (face->font)
                    - FONT_DESCENT (face->font) + 1) / 2;
1091 1092 1093 1094 1095 1096
#endif /* HAVE_NTGUI */
	}
      else
	ascent = height / 2;
    }
  else
1097
    ascent = height * (img->ascent / 100.0);
1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108

  return ascent;
}


/* Image background colors.  */

/* Find the "best" corner color of a bitmap.
   On W32, XIMG is assumed to a device context with the bitmap selected.  */

static RGB_PIXEL_COLOR
1109 1110
four_corners_best (XImagePtr_or_DC ximg, int *corners,
		   unsigned long width, unsigned long height)
1111
{
1112
  RGB_PIXEL_COLOR corner_pixels[4], best IF_LINT (= 0);
1113 1114
  int i, best_count;

1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130
  if (corners && corners[BOT_CORNER] >= 0)
    {
      /* Get the colors at the corner_pixels of ximg.  */
      corner_pixels[0] = GET_PIXEL (ximg, corners[LEFT_CORNER], corners[TOP_CORNER]);
      corner_pixels[1] = GET_PIXEL (ximg, corners[RIGHT_CORNER] - 1, corners[TOP_CORNER]);
      corner_pixels[2] = GET_PIXEL (ximg, corners[RIGHT_CORNER] - 1, corners[BOT_CORNER] - 1);
      corner_pixels[3] = GET_PIXEL (ximg, corners[LEFT_CORNER], corners[BOT_CORNER] - 1);
    }
  else
    {
      /* Get the colors at the corner_pixels of ximg.  */
      corner_pixels[0] = GET_PIXEL (ximg, 0, 0);
      corner_pixels[1] = GET_PIXEL (ximg, width - 1, 0);
      corner_pixels[2] = GET_PIXEL (ximg, width - 1, height - 1);
      corner_pixels[3] = GET_PIXEL (ximg, 0, height - 1);
    }
1131 1132 1133 1134 1135 1136
  /* Choose the most frequently found color as background.  */
  for (i = best_count = 0; i < 4; ++i)
    {
      int j, n;

      for (j = n = 0; j < 4; ++j)
1137
	if (corner_pixels[i] == corner_pixels[j])
1138 1139 1140
	  ++n;

      if (n > best_count)
1141
	best = corner_pixels[i], best_count = n;
1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156
    }

  return best;
}

/* Portability macros */

#ifdef HAVE_NTGUI

#define Destroy_Image(img_dc, prev) \
  do { SelectObject (img_dc, prev); DeleteDC (img_dc); } while (0)

#define Free_Pixmap(display, pixmap) \
  DeleteObject (pixmap)

1157 1158 1159
#elif defined (HAVE_NS)

#define Destroy_Image(ximg, dummy) \
1160
  ns_release_object (ximg)
1161 1162

#define Free_Pixmap(display, pixmap) \
1163
  ns_release_object (pixmap)
1164

1165 1166 1167 1168 1169 1170 1171 1172
#else

#define Destroy_Image(ximg, dummy) \
  XDestroyImage (ximg)

#define Free_Pixmap(display, pixmap) \
  XFreePixmap (display, pixmap)

1173
#endif /* !HAVE_NTGUI && !HAVE_NS */
1174 1175 1176 1177 1178


/* Return the `background' field of IMG.  If IMG doesn't have one yet,
   it is guessed heuristically.  If non-zero, XIMG is an existing
   XImage object (or device context with the image selected on W32) to
Kim F. Storm's avatar
Kim F. Storm committed
1179
   use for the heuristic.  */
1180 1181

RGB_PIXEL_COLOR
1182
image_background (struct image *img, struct frame *f, XImagePtr_or_DC ximg)
1183 1184 1185 1186
{
  if (! img->background_valid)
    /* IMG doesn't have a background yet, try to guess a reasonable value.  */
    {
1187
      bool free_ximg = !ximg;
1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204
#ifdef HAVE_NTGUI
      HGDIOBJ prev;
#endif /* HAVE_NTGUI */

      if (free_ximg)
	{
#ifndef HAVE_NTGUI
	  ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
			    0, 0, img->width, img->height, ~0, ZPixmap);
#else
	  HDC frame_dc = get_frame_dc (f);
	  ximg = CreateCompatibleDC (frame_dc);
	  release_frame_dc (f, frame_dc);
	  prev = SelectObject (ximg, img->pixmap);
#endif /* !HAVE_NTGUI */
	}

1205
      img->background = four_corners_best (ximg, img->corners, img->width, img->height);
1206 1207 1208

      if (free_ximg)
	Destroy_Image (ximg, prev);
Kim F. Storm's avatar
Kim F. Storm committed
1209

1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220
      img->background_valid = 1;
    }

  return img->background;
}

/* Return the `background_transparent' field of IMG.  If IMG doesn't
   have one yet, it is guessed heuristically.  If non-zero, MASK is an
   existing XImage object to use for the heuristic.  */

int
1221
image_background_transparent (struct image *img, struct frame *f, XImagePtr_or_DC mask)
1222 1223 1224 1225 1226 1227
{
  if (! img->background_transparent_valid)
    /* IMG doesn't have a background yet, try to guess a reasonable value.  */
    {
      if (img->mask)
	{
1228
	  bool free_mask = !mask;
1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246
#ifdef HAVE_NTGUI
	  HGDIOBJ prev;
#endif /* HAVE_NTGUI */

	  if (free_mask)
	    {
#ifndef HAVE_NTGUI
	      mask = XGetImage (FRAME_X_DISPLAY (f), img->mask,
				0, 0, img->width, img->height, ~0, ZPixmap);
#else
	      HDC frame_dc = get_frame_dc (f);
	      mask = CreateCompatibleDC (frame_dc);
	      release_frame_dc (f, frame_dc);
	      prev = SelectObject (mask, img->mask);
#endif /* HAVE_NTGUI */
	    }

	  img->background_transparent
1247
	    = (four_corners_best (mask, img->corners, img->width, img->height) == PIX_MASK_RETAIN);
1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265

	  if (free_mask)
	    Destroy_Image (mask, prev);
	}
      else
	img->background_transparent = 0;

      img->background_transparent_valid = 1;
    }

  return img->background_transparent;
}


/***********************************************************************
		  Helper functions for X image types
 ***********************************************************************/