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

Paul Eggert's avatar
Paul Eggert committed
3
Copyright (C) 1989, 1992-2017 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 <https://www.gnu.org/licenses/>.  */
19 20

#include <config.h>
21 22

#include <fcntl.h>
23 24
#include <unistd.h>

25 26 27 28 29 30
/* Include this before including <setjmp.h> to work around bugs with
   older libpng; see Bug#17429.  */
#if defined HAVE_PNG && !defined HAVE_NS
# include <png.h>
#endif

31
#include <setjmp.h>
32

33
#include <c-ctype.h>
34
#include <flexmember.h>
35

36 37
#include "lisp.h"
#include "frame.h"
38
#include "process.h"
39
#include "window.h"
40
#include "buffer.h"
41 42
#include "dispextern.h"
#include "blockinput.h"
43
#include "sysstdio.h"
44 45
#include "systime.h"
#include <epaths.h>
46
#include "coding.h"
47
#include "termhooks.h"
48
#include "font.h"
49

50
#ifdef HAVE_SYS_STAT_H
51
#include <sys/stat.h>
52 53 54 55 56 57 58 59 60
#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 */
61

62 63 64 65 66
/* Work around GCC bug 54561.  */
#if GNUC_PREREQ (4, 3, 0)
# pragma GCC diagnostic ignored "-Wclobbered"
#endif

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

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

#ifdef HAVE_NTGUI
77 78 79

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

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

87 88
#define PIX_MASK_RETAIN	0
#define PIX_MASK_DRAW	1
89 90

#define x_defined_color w32_defined_color
91

92 93
#endif /* HAVE_NTGUI */

94 95 96
#ifdef HAVE_NS
typedef struct ns_bitmap_record Bitmap_Record;

Juanma Barranquero's avatar
Juanma Barranquero committed
97
#define GET_PIXEL(ximg, x, y) XGetPixel (ximg, x, y)
98 99 100 101 102 103 104 105
#define NO_PIXMAP 0

#define PIX_MASK_RETAIN	0

#define x_defined_color(f, name, color_def, alloc) \
  ns_defined_color (f, name, color_def, alloc, 0)
#endif /* HAVE_NS */

106 107 108 109 110 111
#if (defined HAVE_X_WINDOWS \
     && ! (defined HAVE_NTGUI || defined USE_CAIRO || defined HAVE_NS))
/* W32_TODO : Color tables on W32.  */
# define COLOR_TABLE_SUPPORT 1
#endif

112 113 114
static void x_disable_image (struct frame *, struct image *);
static void x_edge_detection (struct frame *, struct image *, Lisp_Object,
                              Lisp_Object);
115

116 117
static void init_color_table (void);
static unsigned long lookup_rgb_color (struct frame *f, int r, int g, int b);
118
#ifdef COLOR_TABLE_SUPPORT
119 120
static void free_color_table (void);
static unsigned long *colors_in_color_table (int *n);
121 122 123 124 125 126 127 128 129 130 131 132 133
#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.  */

134
#ifdef HAVE_NS
Paul Eggert's avatar
Paul Eggert committed
135
/* Use with images created by ns_image_for_XPM.  */
136
static unsigned long
137 138
XGetPixel (XImagePtr ximage, int x, int y)
{
139
  return ns_get_pixel (ximage, x, y);
140 141
}

Paul Eggert's avatar
Paul Eggert committed
142 143
/* Use with images created by ns_image_for_XPM; alpha set to 1;
   pixel is assumed to be in RGB form.  */
144
static void
145 146
XPutPixel (XImagePtr ximage, int x, int y, unsigned long pixel)
{
147
  ns_put_pixel (ximage, x, y, pixel);
148 149 150
}
#endif /* HAVE_NS */

151 152 153

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

154
#ifdef HAVE_X_WINDOWS
155
static int
Dmitry Antipov's avatar
Dmitry Antipov committed
156
x_bitmap_height (struct frame *f, ptrdiff_t id)
157
{
158
  return FRAME_DISPLAY_INFO (f)->bitmaps[id - 1].height;
159 160
}

161
static int
Dmitry Antipov's avatar
Dmitry Antipov committed
162
x_bitmap_width (struct frame *f, ptrdiff_t id)
163
{
164
  return FRAME_DISPLAY_INFO (f)->bitmaps[id - 1].width;
165
}
166
#endif
167 168

#if defined (HAVE_X_WINDOWS) || defined (HAVE_NTGUI)
169
ptrdiff_t
Dmitry Antipov's avatar
Dmitry Antipov committed
170
x_bitmap_pixmap (struct frame *f, ptrdiff_t id)
171
{
172
  /* HAVE_NTGUI needs the explicit cast here.  */
173
  return (ptrdiff_t) FRAME_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
174 175 176 177 178
}
#endif

#ifdef HAVE_X_WINDOWS
int
Dmitry Antipov's avatar
Dmitry Antipov committed
179
x_bitmap_mask (struct frame *f, ptrdiff_t id)
180
{
181
  return FRAME_DISPLAY_INFO (f)->bitmaps[id - 1].mask;
182 183 184 185 186
}
#endif

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

187
static ptrdiff_t
Dmitry Antipov's avatar
Dmitry Antipov committed
188
x_allocate_bitmap_record (struct frame *f)
189
{
190
  Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
191
  ptrdiff_t i;
192 193 194 195 196 197 198 199

  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
200 201 202
  dpyinfo->bitmaps =
    xpalloc (dpyinfo->bitmaps, &dpyinfo->bitmaps_size,
	     10, -1, sizeof *dpyinfo->bitmaps);
203 204 205 206 207 208
  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
209
x_reference_bitmap (struct frame *f, ptrdiff_t id)
210
{
211
  ++FRAME_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
212 213 214 215
}

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

216
ptrdiff_t
217
x_create_bitmap_from_data (struct frame *f, char *bits, unsigned int width, unsigned int height)
218
{
219
  Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
220
  ptrdiff_t id;
221 222 223

#ifdef HAVE_X_WINDOWS
  Pixmap bitmap;
224
  bitmap = XCreateBitmapFromData (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f),
225 226 227 228 229 230
				  bits, width, height);
  if (! bitmap)
    return -1;
#endif /* HAVE_X_WINDOWS */

#ifdef HAVE_NTGUI
231
  Lisp_Object frame UNINIT;	/* The value is not used.  */
232 233
  Pixmap bitmap;
  bitmap = CreateBitmap (width, height,
234 235
			 FRAME_DISPLAY_INFO (XFRAME (frame))->n_planes,
			 FRAME_DISPLAY_INFO (XFRAME (frame))->n_cbits,
236 237 238 239 240
			 bits);
  if (! bitmap)
    return -1;
#endif /* HAVE_NTGUI */

241
#ifdef HAVE_NS
242
  void *bitmap = ns_image_from_XBM (bits, width, height, 0, 0);
243 244 245 246
  if (!bitmap)
      return -1;
#endif

247 248
  id = x_allocate_bitmap_record (f);

249 250 251 252 253
#ifdef HAVE_NS
  dpyinfo->bitmaps[id - 1].img = bitmap;
  dpyinfo->bitmaps[id - 1].depth = 1;
#endif

254 255 256 257 258 259 260
  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;
261
  dpyinfo->bitmaps[id - 1].have_mask = false;
262 263 264 265 266 267 268 269 270 271 272 273 274 275
  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.  */

276
ptrdiff_t
277
x_create_bitmap_from_file (struct frame *f, Lisp_Object file)
278 279 280
{
#ifdef HAVE_NTGUI
  return -1;  /* W32_TODO : bitmap support */
281
#else
282
  Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
283
#endif
284

285
#ifdef HAVE_NS
286
  ptrdiff_t id;
287
  void *bitmap = ns_image_from_file (file);
288 289 290 291 292 293 294 295

  if (!bitmap)
      return -1;


  id = x_allocate_bitmap_record (f);
  dpyinfo->bitmaps[id - 1].img = bitmap;
  dpyinfo->bitmaps[id - 1].refcount = 1;
296
  dpyinfo->bitmaps[id - 1].file = xlispstrdup (file);
297
  dpyinfo->bitmaps[id - 1].depth = 1;
298 299
  dpyinfo->bitmaps[id - 1].height = ns_image_width (bitmap);
  dpyinfo->bitmaps[id - 1].width = ns_image_height (bitmap);
300 301 302
  return id;
#endif

303 304 305
#ifdef HAVE_X_WINDOWS
  unsigned int width, height;
  Pixmap bitmap;
306 307
  int xhot, yhot, result;
  ptrdiff_t id;
308 309 310 311 312 313 314 315
  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
316
	  && !strcmp (dpyinfo->bitmaps[id].file, SSDATA (file)))
317 318 319 320 321 322 323
	{
	  ++dpyinfo->bitmaps[id].refcount;
	  return id + 1;
	}
    }

  /* Search bitmap-file-path for the file, if appropriate.  */
324 325 326
  if (openp (Vx_bitmap_file_path, file, Qnil, &found,
	     make_number (R_OK), false)
      < 0)
327 328
    return -1;

329
  filename = SSDATA (found);
330

331
  result = XReadBitmapFile (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f),
332 333 334 335 336 337
			    filename, &width, &height, &bitmap, &xhot, &yhot);
  if (result != BitmapSuccess)
    return -1;

  id = x_allocate_bitmap_record (f);
  dpyinfo->bitmaps[id - 1].pixmap = bitmap;
338
  dpyinfo->bitmaps[id - 1].have_mask = false;
339
  dpyinfo->bitmaps[id - 1].refcount = 1;
340
  dpyinfo->bitmaps[id - 1].file = xlispstrdup (file);
341 342 343 344 345 346 347 348 349 350 351
  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
352
free_bitmap_record (Display_Info *dpyinfo, Bitmap_Record *bm)
353 354 355 356 357 358 359 360 361 362 363
{
#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 */

364
#ifdef HAVE_NS
365
  ns_release_object (bm->img);
366 367
#endif

368 369 370 371 372 373 374 375 376 377
  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
378
x_destroy_bitmap (struct frame *f, ptrdiff_t id)
379
{
380
  Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
381 382 383 384 385 386 387

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

      if (--bm->refcount == 0)
	{
388
	  block_input ();
389
	  free_bitmap_record (dpyinfo, bm);
390
	  unblock_input ();
391 392 393 394 395 396 397
	}
    }
}

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

void
398
x_destroy_all_bitmaps (Display_Info *dpyinfo)
399
{
400
  ptrdiff_t i;
401 402 403 404
  Bitmap_Record *bm = dpyinfo->bitmaps;

  for (i = 0; i < dpyinfo->bitmaps_last; i++, bm++)
    if (bm->refcount > 0)
405
      free_bitmap_record (dpyinfo, bm);
406 407 408 409

  dpyinfo->bitmaps_last = 0;
}

410 411 412
static bool x_create_x_image_and_pixmap (struct frame *, int, int, int,
					 XImagePtr *, Pixmap *);
static void x_destroy_x_image (XImagePtr ximg);
413

414 415 416 417 418 419 420 421 422 423 424 425 426 427
#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

428 429
#ifdef HAVE_X_WINDOWS

430 431
static void image_sync_to_pixmaps (struct frame *, struct image *);

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

435 436 437 438
static unsigned long four_corners_best (XImagePtr ximg,
                                        int *corners,
                                        unsigned long width,
                                        unsigned long height);
439 440 441 442 443


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

444
void
445
x_create_bitmap_mask (struct frame *f, ptrdiff_t id)
446 447 448 449
{
  Pixmap pixmap, mask;
  XImagePtr ximg, mask_img;
  unsigned long width, height;
450
  bool result;
451 452 453 454
  unsigned long bg;
  unsigned long x, y, xp, xm, yp, ym;
  GC gc;

455
  Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
456 457

  if (!(id > 0))
458
    return;
459 460 461 462 463

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

464
  block_input ();
465 466 467 468 469
  ximg = XGetImage (FRAME_X_DISPLAY (f), pixmap, 0, 0, width, height,
		    ~0, ZPixmap);

  if (!ximg)
    {
470
      unblock_input ();
471
      return;
472 473 474 475
    }

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

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

483
  bg = four_corners_best (ximg, NULL, width, height);
484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507

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

508
  eassert (input_blocked_p ());
509 510 511 512 513
  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);

514
  dpyinfo->bitmaps[id - 1].have_mask = true;
515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531
  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;

532
/* Forward function prototypes.  */
533

Chong Yidong's avatar
Chong Yidong committed
534
static struct image_type *lookup_image_type (Lisp_Object);
535 536
static void x_laplace (struct frame *, struct image *);
static void x_emboss (struct frame *, struct image *);
537
static void x_build_heuristic_mask (struct frame *, struct image *,
Daniel Colascione's avatar
Daniel Colascione committed
538
                                    Lisp_Object);
Daniel Colascione's avatar
Daniel Colascione committed
539
#ifdef WINDOWSNT
540
#define CACHE_IMAGE_TYPE(type, status) \
541
  do { Vlibrary_cache = Fcons (Fcons (type, status), Vlibrary_cache); } while (0)
542 543
#else
#define CACHE_IMAGE_TYPE(type, status)
544
#endif
545 546 547

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

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

Chong Yidong's avatar
Chong Yidong committed
552
static struct image_type *
553
define_image_type (struct image_type *type)
554
{
Chong Yidong's avatar
Chong Yidong committed
555
  struct image_type *p = NULL;
Paul Eggert's avatar
Paul Eggert committed
556 557
  int new_type = type->type;
  bool type_valid = true;
558

559
  block_input ();
Chong Yidong's avatar
Chong Yidong committed
560 561

  for (p = image_types; p; p = p->next)
562
    if (p->type == new_type)
Chong Yidong's avatar
Chong Yidong committed
563 564 565
      goto done;

  if (type->init)
566
    {
567
#if defined HAVE_NTGUI && defined WINDOWSNT
Chong Yidong's avatar
Chong Yidong committed
568
      /* If we failed to load the library before, don't try again.  */
Paul Eggert's avatar
Paul Eggert committed
569 570
      Lisp_Object tested = Fassq (builtin_lisp_symbol (new_type),
				  Vlibrary_cache);
Chong Yidong's avatar
Chong Yidong committed
571
      if (CONSP (tested) && NILP (XCDR (tested)))
Paul Eggert's avatar
Paul Eggert committed
572
	type_valid = false;
Chong Yidong's avatar
Chong Yidong committed
573 574 575
      else
#endif
	{
576
	  type_valid = type->init ();
Paul Eggert's avatar
Paul Eggert committed
577
	  CACHE_IMAGE_TYPE (builtin_lisp_symbol (new_type),
578
			    type_valid ? Qt : Qnil);
Chong Yidong's avatar
Chong Yidong committed
579 580
	}
    }
581

Chong Yidong's avatar
Chong Yidong committed
582
  if (type_valid)
583 584 585
    {
      /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
         The initialized data segment is read-only.  */
586
      p = xmalloc (sizeof *p);
587
      *p = *type;
588 589 590 591
      p->next = image_types;
      image_types = p;
    }

Chong Yidong's avatar
Chong Yidong committed
592
 done:
593
  unblock_input ();
Chong Yidong's avatar
Chong Yidong committed
594
  return p;
595 596 597
}


598
/* Value is true if OBJECT is a valid Lisp image specification.  A
599 600 601 602 603 604
   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.  */

605
bool
606
valid_image_p (Lisp_Object object)
607
{
608
  bool valid_p = 0;
609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633

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


Paul Eggert's avatar
Paul Eggert committed
634
/* Log error message with format string FORMAT and trailing arguments.
635 636 637 638 639 640
   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
Paul Eggert's avatar
Paul Eggert committed
641
image_error (const char *format, ...)
642
{
Paul Eggert's avatar
Paul Eggert committed
643 644 645 646
  va_list ap;
  va_start (ap, format);
  vadd_to_log (format, ap);
  va_end (ap);
647 648
}

649 650 651
static void
image_size_error (void)
{
652
  image_error ("Invalid image size (see `max-image-size')");
653
}
654 655 656 657 658 659 660 661 662 663 664 665 666


/***********************************************************************
			 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,
667
  IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR,
668 669 670 671 672 673 674 675 676 677 678 679 680
  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.  */
681
  const char *name;
682 683 684 685

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

686 687
  /* True means key must be present.  */
  bool mandatory_p;
688 689 690 691 692 693 694 695 696 697 698 699 700

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

703
static bool
704 705
parse_image_spec (Lisp_Object spec, struct image_keyword *keywords,
		  int nkeywords, Lisp_Object type)
706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731
{
  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)
732
	if (strcmp (keywords[i].name, SSDATA (SYMBOL_NAME (key))) == 0)
733 734 735 736 737 738 739 740 741 742
	  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;
743
      ++keywords[i].count;
744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763

      /* 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:
764
	  if (! RANGED_INTEGERP (1, value, INT_MAX))
765 766 767
	    return 0;
	  break;

768 769
	case IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR:
	  if (RANGED_INTEGERP (0, value, INT_MAX))
770 771
	    break;
	  if (CONSP (value)
772 773
	      && RANGED_INTEGERP (0, XCAR (value), INT_MAX)
	      && RANGED_INTEGERP (0, XCDR (value), INT_MAX))
774 775 776 777 778 779
	    break;
	  return 0;

	case IMAGE_ASCENT_VALUE:
	  if (SYMBOLP (value) && EQ (value, Qcenter))
	    break;
780
	  else if (RANGED_INTEGERP (0, value, 100))
781 782 783 784
	    break;
	  return 0;

	case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
785 786 787
	  /* Unlike the other integer-related cases, this one does not
	     verify that VALUE fits in 'int'.  This is because callers
	     want EMACS_INT.  */
788 789 790 791 792 793 794 795 796
	  if (!INTEGERP (value) || XINT (value) < 0)
	    return 0;
	  break;

	case IMAGE_DONT_CHECK_VALUE_TYPE:
	  break;

	case IMAGE_FUNCTION_VALUE:
	  value = indirect_function (value);
797
	  if (FUNCTIONP (value))
798 799 800 801
	    break;
	  return 0;

	case IMAGE_NUMBER_VALUE:
802
	  if (! NUMBERP (value))
803 804 805 806
	    return 0;
	  break;

	case IMAGE_INTEGER_VALUE:
807
	  if (! TYPE_RANGED_INTEGERP (int, value))
808 809 810 811 812 813 814 815 816
	    return 0;
	  break;

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

	default:
817
	  emacs_abort ();
818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834
	  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
835 836
   if KEY is not present in SPEC.  Set *FOUND depending on whether KEY
   was found in SPEC.  */
837 838

static Lisp_Object
839
image_spec_value (Lisp_Object spec, Lisp_Object key, bool *found)
840 841 842
{
  Lisp_Object tail;

843
  eassert (valid_image_p (spec));
844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868

  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
869
  (Lisp_Object spec, Lisp_Object pixels, Lisp_Object frame)
870 871 872 873 874 875
{
  Lisp_Object size;

  size = Qnil;
  if (valid_image_p (spec))
    {
876
      struct frame *f = decode_window_system_frame (frame);
877
      ptrdiff_t id = lookup_image (f, spec);
878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898
      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
899
  (Lisp_Object spec, Lisp_Object frame)
900 901 902 903 904 905
{
  Lisp_Object mask;

  mask = Qnil;
  if (valid_image_p (spec))
    {
906
      struct frame *f = decode_window_system_frame (frame);
907
      ptrdiff_t id = lookup_image (f, spec);
908 909 910 911 912 913 914 915 916 917
      struct image *img = IMAGE_FROM_ID (f, id);
      if (img->mask)
	mask = Qt;
    }
  else
    error ("Invalid image specification");

  return mask;
}

918 919
DEFUN ("image-metadata", Fimage_metadata, Simage_metadata, 1, 2, 0,
       doc: /* Return metadata for image SPEC.
920 921
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
922
  (Lisp_Object spec, Lisp_Object frame)
923 924 925 926 927 928
{
  Lisp_Object ext;

  ext = Qnil;
  if (valid_image_p (spec))
    {
929
      struct frame *f = decode_window_system_frame (frame);
930
      ptrdiff_t id = lookup_image (f, spec);
931
      struct image *img = IMAGE_FROM_ID (f, id);
Chong Yidong's avatar
Chong Yidong committed
932
      ext = img->lisp_data;
933 934 935 936 937
    }

  return ext;
}

938 939 940 941 942

/***********************************************************************
		 Image type independent image structures
 ***********************************************************************/

943
#define MAX_IMAGE_SIZE 10.0
944 945 946 947
/* Allocate and return a new image structure for image specification
   SPEC.  SPEC has a hash value of HASH.  */

static struct image *
948
make_image (Lisp_Object spec, EMACS_UINT hash)
949
{
Dmitry Antipov's avatar
Dmitry Antipov committed
950
  struct image *img = xzalloc (sizeof *img);
951
  Lisp_Object file = image_spec_value (spec, QCfile, NULL);
952

953
  eassert (valid_image_p (spec));
954
  img->dependencies = NILP (file) ? Qnil : list1 (file);
955
  img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
956
  eassert (img->type != NULL);
957
  img->spec = spec;
Chong Yidong's avatar
Chong Yidong committed
958
  img->lisp_data = Qnil;
959 960
  img->ascent = DEFAULT_IMAGE_ASCENT;
  img->hash = hash;
961
  img->corners[BOT_CORNER] = -1;  /* Full image */
962 963 964 965 966 967 968
  return img;
}


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

static void
969
free_image (struct frame *f, struct image *img)
970 971 972
{
  if (img)
    {
973
      struct image_cache *c = FRAME_IMAGE_CACHE (f);
974 975 976 977 978 979 980 981 982 983 984 985

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

986 987 988 989 990
      /* Windows NT redefines 'free', but in this file, we need to
         avoid the redefinition.  */
#ifdef WINDOWSNT
#undef free
#endif
991 992 993 994 995 996
      /* Free resources, then free IMG.  */
      img->type->free (f, img);
      xfree (img);
    }
}

997
/* Return true if the given widths and heights are valid for display.  */
998

999
static bool
1000
check_image_size (struct frame *f, int width, int height)
1001
{
1002
  int w, h;
1003

1004
  if (width <= 0 || height <= 0)
1005 1006
    return 0;

1007
  if (INTEGERP (Vmax_image_size))
1008 1009
    return (width <= XINT (Vmax_image_size)
	    && height <= XINT (Vmax_image_size));
1010 1011
  else if (FLOATP (Vmax_image_size))
    {
1012 1013 1014 1015 1016 1017 1018
      if (f != NULL)
	{
	  w = FRAME_PIXEL_WIDTH (f);
	  h = FRAME_PIXEL_HEIGHT (f);
	}
      else
	w = h = 1024;  /* Arbitrary size for unknown frame. */
1019 1020
      return (width <= XFLOAT_DATA (Vmax_image_size) * w
	      && height <= XFLOAT_DATA (Vmax_image_size) * h);
1021 1022 1023
    }
  else
    return 1;
1024
}
1025 1026 1027 1028 1029

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

void
1030
prepare_image_for_display (struct frame *f, struct image *img)
1031 1032
{
  /* We're about to display IMG, so set its timestamp to `now'.  */
1033
  img->timestamp = current_timespec ();
1034

1035
#ifndef USE_CAIRO
1036 1037 1038
  /* 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)
1039
    img->load_failed_p = ! img->type->load (f, img);
1040

1041 1042 1043 1044 1045 1046 1047 1048
#ifdef HAVE_X_WINDOWS
  if (!img->load_failed_p)
    {
      block_input ();
      image_sync_to_pixmaps (f, img);
      unblock_input ();
    }
#endif
1049
#endif
1050 1051 1052 1053 1054 1055 1056
}


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

int
1057
image_ascent (struct image *img, struct face *face, struct glyph_slice *slice)
1058
{
1059
  int height;
1060 1061
  int ascent;

1062 1063 1064 1065 1066 1067 1068
  if (slice->height == img->height)
    height = img->height + img->vmargin;
  else if (slice->y == 0)
    height = slice->height + img->vmargin;
  else
    height = slice->height;

1069 1070 1071 1072 1073 1074
  if (img->ascent == CENTERED_IMAGE_ASCENT)
    {
      if (face->font)
	{
#ifdef HAVE_NTGUI
	  /* W32 specific version.  Why?. ++kfs  */
1075 1076
	  ascent = height / 2 - (FONT_DESCENT (face->font)
				 - FONT_BASE (face->font)) / 2;
1077 1078 1079 1080 1081 1082
#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
1083 1084
	  ascent = (height + FONT_BASE (face->font)
                    - FONT_DESCENT (face->font) + 1) / 2;
1085 1086 1087 1088 1089 1090
#endif /* HAVE_NTGUI */
	}
      else
	ascent = height / 2;
    }
  else
1091
    ascent = height * (img->ascent / 100.0);
1092 1093 1094 1095

  return ascent;
}

1096
#ifdef USE_CAIRO
Jan D's avatar
Jan D committed
1097 1098 1099
static uint32_t
xcolor_to_argb32 (XColor xc)
{
1100 1101
  return ((0xffu << 24) | ((xc.red / 256) << 16)
	  | ((xc.green / 256) << 8) | (xc.blue / 256));
Jan D's avatar
Jan D committed
1102 1103
}

1104 1105 1106 1107 1108 1109 1110 1111
static uint32_t
get_spec_bg_or_alpha_as_argb (struct image *img,
                              struct frame *f)
{
  uint32_t bgcolor = 0;
  XColor xbgcolor;
  Lisp_Object bg = image_spec_value (img->spec, QCbackground, NULL);

1112
  if (STRINGP (bg) && x_parse_color (f, SSDATA (bg), &xbgcolor))