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

3
Copyright (C) 1989, 1992-2013 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

#include <config.h>
21
#include "sysstdio.h"
22 23
#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
#define NO_PIXMAP None

71 72
#define PIX_MASK_RETAIN	0
#define PIX_MASK_DRAW	1
73 74 75
#endif /* HAVE_X_WINDOWS */

#ifdef HAVE_NTGUI
76 77 78

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

82 83 84 85
/* W32_TODO : Color tables on W32.  */
#undef COLOR_TABLE_SUPPORT

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

89 90
#define PIX_MASK_RETAIN	0
#define PIX_MASK_DRAW	1
91 92 93

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

95 96 97 98
/* 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;
99 100
#endif /* HAVE_NTGUI */

101 102 103 104 105
#ifdef HAVE_NS
#undef COLOR_TABLE_SUPPORT

typedef struct ns_bitmap_record Bitmap_Record;

Juanma Barranquero's avatar
Juanma Barranquero committed
106
#define GET_PIXEL(ximg, x, y) XGetPixel (ximg, x, y)
107 108 109 110 111 112 113
#define NO_PIXMAP 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)
114
#define DefaultDepthOfScreen(screen) x_display_list->n_planes
115 116 117
#endif /* HAVE_NS */


118 119
/* The symbol `postscript' identifying images of this type.  */

120
static Lisp_Object Qpostscript;
121

122 123 124
static void x_disable_image (struct frame *, struct image *);
static void x_edge_detection (struct frame *, struct image *, Lisp_Object,
                              Lisp_Object);
125

126 127
static void init_color_table (void);
static unsigned long lookup_rgb_color (struct frame *f, int r, int g, int b);
128
#ifdef COLOR_TABLE_SUPPORT
129 130
static void free_color_table (void);
static unsigned long *colors_in_color_table (int *n);
131 132
#endif

133
static Lisp_Object QCmax_width, QCmax_height;
134

135 136 137 138 139 140 141 142 143 144 145
/* 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.  */

146
#ifdef HAVE_NS
Paul Eggert's avatar
Paul Eggert committed
147
/* Use with images created by ns_image_for_XPM.  */
148 149 150
unsigned long
XGetPixel (XImagePtr ximage, int x, int y)
{
151
  return ns_get_pixel (ximage, x, y);
152 153
}

Paul Eggert's avatar
Paul Eggert committed
154 155
/* Use with images created by ns_image_for_XPM; alpha set to 1;
   pixel is assumed to be in RGB form.  */
156 157 158
void
XPutPixel (XImagePtr ximage, int x, int y, unsigned long pixel)
{
159
  ns_put_pixel (ximage, x, y, pixel);
160 161 162
}
#endif /* HAVE_NS */

163 164 165 166

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

int
Dmitry Antipov's avatar
Dmitry Antipov committed
167
x_bitmap_height (struct frame *f, ptrdiff_t id)
168 169 170 171 172
{
  return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].height;
}

int
Dmitry Antipov's avatar
Dmitry Antipov committed
173
x_bitmap_width (struct frame *f, ptrdiff_t id)
174 175 176 177 178
{
  return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].width;
}

#if defined (HAVE_X_WINDOWS) || defined (HAVE_NTGUI)
179
ptrdiff_t
Dmitry Antipov's avatar
Dmitry Antipov committed
180
x_bitmap_pixmap (struct frame *f, ptrdiff_t id)
181
{
182
  /* HAVE_NTGUI needs the explicit cast here.  */
183
  return (ptrdiff_t) FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
184 185 186 187 188
}
#endif

#ifdef HAVE_X_WINDOWS
int
Dmitry Antipov's avatar
Dmitry Antipov committed
189
x_bitmap_mask (struct frame *f, ptrdiff_t id)
190 191 192 193 194 195 196
{
  return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].mask;
}
#endif

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

197
static ptrdiff_t
Dmitry Antipov's avatar
Dmitry Antipov committed
198
x_allocate_bitmap_record (struct frame *f)
199 200
{
  Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
201
  ptrdiff_t i;
202 203 204 205 206 207 208 209

  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
210 211 212
  dpyinfo->bitmaps =
    xpalloc (dpyinfo->bitmaps, &dpyinfo->bitmaps_size,
	     10, -1, sizeof *dpyinfo->bitmaps);
213 214 215 216 217 218
  return ++dpyinfo->bitmaps_last;
}

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

void
Dmitry Antipov's avatar
Dmitry Antipov committed
219
x_reference_bitmap (struct frame *f, ptrdiff_t id)
220 221 222 223 224 225
{
  ++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.  */

226
ptrdiff_t
227
x_create_bitmap_from_data (struct frame *f, char *bits, unsigned int width, unsigned int height)
228 229
{
  Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
230
  ptrdiff_t id;
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249

#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 */

250
#ifdef HAVE_NS
251
  void *bitmap = ns_image_from_XBM (bits, width, height);
252 253 254 255
  if (!bitmap)
      return -1;
#endif

256 257
  id = x_allocate_bitmap_record (f);

258 259 260 261 262
#ifdef HAVE_NS
  dpyinfo->bitmaps[id - 1].img = bitmap;
  dpyinfo->bitmaps[id - 1].depth = 1;
#endif

263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
  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.  */

285
ptrdiff_t
286
x_create_bitmap_from_file (struct frame *f, Lisp_Object file)
287
{
288 289
  Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);

290 291 292 293
#ifdef HAVE_NTGUI
  return -1;  /* W32_TODO : bitmap support */
#endif /* HAVE_NTGUI */

294
#ifdef HAVE_NS
295
  ptrdiff_t id;
296
  void *bitmap = ns_image_from_file (file);
297 298 299 300 301 302 303 304

  if (!bitmap)
      return -1;


  id = x_allocate_bitmap_record (f);
  dpyinfo->bitmaps[id - 1].img = bitmap;
  dpyinfo->bitmaps[id - 1].refcount = 1;
305
  dpyinfo->bitmaps[id - 1].file = xlispstrdup (file);
306
  dpyinfo->bitmaps[id - 1].depth = 1;
307 308
  dpyinfo->bitmaps[id - 1].height = ns_image_width (bitmap);
  dpyinfo->bitmaps[id - 1].width = ns_image_height (bitmap);
309 310 311
  return id;
#endif

312 313 314
#ifdef HAVE_X_WINDOWS
  unsigned int width, height;
  Pixmap bitmap;
315 316
  int xhot, yhot, result;
  ptrdiff_t id;
317 318 319 320 321 322 323 324
  Lisp_Object found;
  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
325
	  && !strcmp (dpyinfo->bitmaps[id].file, SSDATA (file)))
326 327 328 329 330 331 332
	{
	  ++dpyinfo->bitmaps[id].refcount;
	  return id + 1;
	}
    }

  /* Search bitmap-file-path for the file, if appropriate.  */
333
  if (openp (Vx_bitmap_file_path, file, Qnil, &found, make_number (R_OK)) < 0)
334 335
    return -1;

336
  filename = SSDATA (found);
337 338 339 340 341 342 343 344 345 346

  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;
347
  dpyinfo->bitmaps[id - 1].file = xlispstrdup (file);
348 349 350 351 352 353 354 355 356 357 358
  dpyinfo->bitmaps[id - 1].depth = 1;
  dpyinfo->bitmaps[id - 1].height = height;
  dpyinfo->bitmaps[id - 1].width = width;

  return id;
#endif /* HAVE_X_WINDOWS */
}

/* Free bitmap B.  */

static void
359
free_bitmap_record (Display_Info *dpyinfo, Bitmap_Record *bm)
360 361 362 363 364 365 366 367 368 369 370
{
#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 */

371
#ifdef HAVE_NS
372
  ns_release_object (bm->img);
373 374
#endif

375 376 377 378 379 380 381 382 383 384
  if (bm->file)
    {
      xfree (bm->file);
      bm->file = NULL;
    }
}

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

void
Dmitry Antipov's avatar
Dmitry Antipov committed
385
x_destroy_bitmap (struct frame *f, ptrdiff_t id)
386 387 388 389 390 391 392 393 394
{
  Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);

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

      if (--bm->refcount == 0)
	{
395
	  block_input ();
396
	  free_bitmap_record (dpyinfo, bm);
397
	  unblock_input ();
398 399 400 401 402 403 404
	}
    }
}

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

void
405
x_destroy_all_bitmaps (Display_Info *dpyinfo)
406
{
407
  ptrdiff_t i;
408 409 410 411
  Bitmap_Record *bm = dpyinfo->bitmaps;

  for (i = 0; i < dpyinfo->bitmaps_last; i++, bm++)
    if (bm->refcount > 0)
412
      free_bitmap_record (dpyinfo, bm);
413 414 415 416

  dpyinfo->bitmaps_last = 0;
}

417 418 419
static bool x_create_x_image_and_pixmap (struct frame *, int, int, int,
					 XImagePtr *, Pixmap *);
static void x_destroy_x_image (XImagePtr ximg);
420

421 422 423 424 425 426 427 428 429 430 431 432 433 434
#ifdef HAVE_NTGUI
static XImagePtr_or_DC image_get_x_image_or_dc (struct frame *, struct image *,
						bool, HGDIOBJ *);
static void image_unget_x_image_or_dc (struct image *, bool, XImagePtr_or_DC,
				       HGDIOBJ);
#else
static XImagePtr image_get_x_image (struct frame *, struct image *, bool);
static void image_unget_x_image (struct image *, bool, XImagePtr);
#define image_get_x_image_or_dc(f, img, mask_p, dummy)	\
  image_get_x_image (f, img, mask_p)
#define image_unget_x_image_or_dc(img, mask_p, ximg, dummy)	\
  image_unget_x_image (img, mask_p, ximg)
#endif

435 436
#ifdef HAVE_X_WINDOWS

437 438
static void image_sync_to_pixmaps (struct frame *, struct image *);

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

442 443 444 445
static unsigned long four_corners_best (XImagePtr ximg,
                                        int *corners,
                                        unsigned long width,
                                        unsigned long height);
446 447 448 449 450


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

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

  Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);

  if (!(id > 0))
465
    return;
466 467 468 469 470

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

471
  block_input ();
472 473 474 475 476
  ximg = XGetImage (FRAME_X_DISPLAY (f), pixmap, 0, 0, width, height,
		    ~0, ZPixmap);

  if (!ximg)
    {
477
      unblock_input ();
478
      return;
479 480 481 482
    }

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

483
  unblock_input ();
484 485 486
  if (!result)
    {
      XDestroyImage (ximg);
487
      return;
488 489
    }

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

  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);
	}
    }

515
  eassert (input_blocked_p ());
516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541
  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.  */

542
static Lisp_Object Qxbm;
543 544 545

/* Keywords.  */

546 547 548 549 550 551
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;
552 553 554

/* Other symbols.  */

555
static Lisp_Object Qcount, Qextension_data, Qdelay;
556
static Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
557

558
/* Forward function prototypes.  */
559

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

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

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

Chong Yidong's avatar
Chong Yidong committed
579
static struct image_type *
580
define_image_type (struct image_type *type)
581
{
Chong Yidong's avatar
Chong Yidong committed
582 583
  struct image_type *p = NULL;
  Lisp_Object target_type = *type->type;
584
  bool type_valid = 1;
585

586
  block_input ();
Chong Yidong's avatar
Chong Yidong committed
587 588 589 590 591 592

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

  if (type->init)
593
    {
594
#if defined HAVE_NTGUI && defined WINDOWSNT
Chong Yidong's avatar
Chong Yidong committed
595 596 597 598 599 600 601
      /* 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
	{
602
	  type_valid = type->init ();
Chong Yidong's avatar
Chong Yidong committed
603 604 605
	  CACHE_IMAGE_TYPE (target_type, type_valid ? Qt : Qnil);
	}
    }
606

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

Chong Yidong's avatar
Chong Yidong committed
617
 done:
618
  unblock_input ();
Chong Yidong's avatar
Chong Yidong committed
619
  return p;
620 621 622
}


623
/* Value is true if OBJECT is a valid Lisp image specification.  A
624 625 626 627 628 629
   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.  */

630
bool
631
valid_image_p (Lisp_Object object)
632
{
633
  bool valid_p = 0;
634 635 636 637 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

  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
666
image_error (const char *format, Lisp_Object arg1, Lisp_Object arg2)
667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683
{
  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,
684
  IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR,
685 686 687 688 689 690 691 692 693 694 695 696 697
  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.  */
698
  const char *name;
699 700 701 702

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

703 704
  /* True means key must be present.  */
  bool mandatory_p;
705 706 707 708 709 710 711 712 713 714 715 716 717

  /* 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
718
   allowed keyword/value pairs.  Value is true if SPEC is valid.  */
719

720
static bool
721 722
parse_image_spec (Lisp_Object spec, struct image_keyword *keywords,
		  int nkeywords, Lisp_Object type)
723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748
{
  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)
749
	if (strcmp (keywords[i].name, SSDATA (SYMBOL_NAME (key))) == 0)
750 751 752 753 754 755 756 757 758 759
	  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;
760
      ++keywords[i].count;
761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780

      /* 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:
781
	  if (! RANGED_INTEGERP (1, value, INT_MAX))
782 783 784
	    return 0;
	  break;

785 786
	case IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR:
	  if (RANGED_INTEGERP (0, value, INT_MAX))
787 788
	    break;
	  if (CONSP (value)
789 790
	      && RANGED_INTEGERP (0, XCAR (value), INT_MAX)
	      && RANGED_INTEGERP (0, XCDR (value), INT_MAX))
791 792 793 794 795 796
	    break;
	  return 0;

	case IMAGE_ASCENT_VALUE:
	  if (SYMBOLP (value) && EQ (value, Qcenter))
	    break;
797
	  else if (RANGED_INTEGERP (0, value, 100))
798 799 800 801
	    break;
	  return 0;

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

	case IMAGE_DONT_CHECK_VALUE_TYPE:
	  break;

	case IMAGE_FUNCTION_VALUE:
	  value = indirect_function (value);
814
	  if (!NILP (Ffunctionp (value)))
815 816 817 818 819 820 821 822 823
	    break;
	  return 0;

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

	case IMAGE_INTEGER_VALUE:
824
	  if (! TYPE_RANGED_INTEGERP (int, value))
825 826 827 828 829 830 831 832 833
	    return 0;
	  break;

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

	default:
834
	  emacs_abort ();
835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851
	  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
852 853
   if KEY is not present in SPEC.  Set *FOUND depending on whether KEY
   was found in SPEC.  */
854 855

static Lisp_Object
856
image_spec_value (Lisp_Object spec, Lisp_Object key, bool *found)
857 858 859
{
  Lisp_Object tail;

860
  eassert (valid_image_p (spec));
861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885

  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
886
  (Lisp_Object spec, Lisp_Object pixels, Lisp_Object frame)
887 888 889 890 891 892
{
  Lisp_Object size;

  size = Qnil;
  if (valid_image_p (spec))
    {
893
      struct frame *f = decode_window_system_frame (frame);
894
      ptrdiff_t id = lookup_image (f, spec);
895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915
      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
916
  (Lisp_Object spec, Lisp_Object frame)
917 918 919 920 921 922
{
  Lisp_Object mask;

  mask = Qnil;
  if (valid_image_p (spec))
    {
923
      struct frame *f = decode_window_system_frame (frame);
924
      ptrdiff_t id = lookup_image (f, spec);
925 926 927 928 929 930 931 932 933 934
      struct image *img = IMAGE_FROM_ID (f, id);
      if (img->mask)
	mask = Qt;
    }
  else
    error ("Invalid image specification");

  return mask;
}

935 936
DEFUN ("image-metadata", Fimage_metadata, Simage_metadata, 1, 2, 0,
       doc: /* Return metadata for image SPEC.
937 938
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
939
  (Lisp_Object spec, Lisp_Object frame)
940 941 942 943 944 945
{
  Lisp_Object ext;

  ext = Qnil;
  if (valid_image_p (spec))
    {
946
      struct frame *f = decode_window_system_frame (frame);
947
      ptrdiff_t id = lookup_image (f, spec);
948
      struct image *img = IMAGE_FROM_ID (f, id);
Chong Yidong's avatar
Chong Yidong committed
949
      ext = img->lisp_data;
950 951 952 953 954
    }

  return ext;
}

955 956 957 958 959

/***********************************************************************
		 Image type independent image structures
 ***********************************************************************/

960
#define MAX_IMAGE_SIZE 10.0
961 962 963 964
/* Allocate and return a new image structure for image specification
   SPEC.  SPEC has a hash value of HASH.  */

static struct image *
965
make_image (Lisp_Object spec, EMACS_UINT hash)
966
{
Dmitry Antipov's avatar
Dmitry Antipov committed
967
  struct image *img = xzalloc (sizeof *img);
968
  Lisp_Object file = image_spec_value (spec, QCfile, NULL);
969

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


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

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

      /* 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);
    }
}

1009
/* Return true if the given widths and heights are valid for display.  */
1010

1011
static bool
1012
check_image_size (struct frame *f, int width, int height)
1013
{
1014
  int w, h;
1015

1016
  if (width <= 0 || height <= 0)
1017 1018
    return 0;

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

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

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

  /* 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)
1050
    img->load_failed_p = ! img->type->load (f, img);
1051

1052 1053 1054 1055 1056 1057 1058 1059
#ifdef HAVE_X_WINDOWS
  if (!img->load_failed_p)
    {
      block_input ();
      image_sync_to_pixmaps (f, img);
      unblock_input ();
    }
#endif
1060 1061 1062 1063 1064 1065 1066
}


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

int
1067
image_ascent (struct image *img, struct face *face, struct glyph_slice *slice)
1068
{
1069
  int height;
1070 1071
  int ascent;

1072 1073 1074 1075 1076 1077 1078
  if (slice->height == img->height)
    height = img->height + img->vmargin;
  else if (slice->y == 0)
    height = slice->height + img->vmargin;
  else
    height = slice->height;

1079 1080 1081 1082 1083 1084
  if (img->ascent == CENTERED_IMAGE_ASCENT)
    {
      if (face->font)
	{
#ifdef HAVE_NTGUI
	  /* W32 specific version.  Why?. ++kfs  */
1085 1086
	  ascent = height / 2 - (FONT_DESCENT (face->font)
				 - FONT_BASE (face->font)) / 2;
1087 1088 1089 1090 1091 1092
#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
1093 1094
	  ascent = (height + FONT_BASE (face->font)
                    - FONT_DESCENT (face->font) + 1) / 2;
1095 1096 1097 1098 1099 1100
#endif /* HAVE_NTGUI */
	}
      else
	ascent = height / 2;
    }
  else
1101
    ascent = height * (img->ascent / 100.0);
1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112

  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
1113 1114
four_corners_best (XImagePtr_or_DC ximg, int *corners,
		   unsigned long width, unsigned long height)
1115
{
1116
  RGB_PIXEL_COLOR corner_pixels[4], best IF_LINT (= 0);
1117 1118
  int i, best_count;

1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134
  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);
    }
1135 1136 1137 1138 1139 1140
  /* 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)
1141
	if (corner_pixels[i] == corner_pixels[j])
1142 1143 1144
	  ++n;

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

  return best;
}

/* Portability macros */

#ifdef HAVE_NTGUI

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

1158 1159 1160
#elif defined (HAVE_NS)

#define Free_Pixmap(display, pixmap) \
1161
  ns_release_object (pixmap)
1162

1163 1164 1165 1166 1167
#else

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

1168
#endif /* !HAVE_NTGUI && !HAVE_NS */
1169 1170 1171 1172 1173


/* 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
1174
   use for the heuristic.  */
1175 1176

RGB_PIXEL_COLOR
1177
image_background (struct image *img, struct frame *f, XImagePtr_or_DC ximg)
1178 1179 1180 1181
{
  if (! img->background_valid)
    /* IMG doesn't have a background yet, try to guess a reasonable value.  */
    {
1182
      bool free_ximg = !ximg;
1183 1184 1185 1186 1187
#ifdef HAVE_NTGUI
      HGDIOBJ prev;
#endif /* HAVE_NTGUI */

      if (free_ximg)
1188
	ximg = image_get_x_image_or_dc (f, img, 0, &prev);
1189

1190
      img->background = four_corners_best (ximg, img->corners, img->width, img->height);
1191 1192

      if (free_ximg)
1193
	image_unget_x_image_or_dc (img, 0, ximg, prev);
Kim F. Storm's avatar
Kim F. Storm committed
1194

1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205
      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
1206
image_background_transparent (struct image *img, struct frame *f, XImagePtr_or_DC mask)
1207 1208 1209 1210 1211 1212
{
  if (! img->background_transparent_valid)
    /* IMG doesn't have a background yet, try to guess a reasonable value.  */
    {
      if (img->mask)
	{
1213
	  bool free_mask = !mask;
1214 1215 1216