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

Paul Eggert's avatar
Paul Eggert committed
3
Copyright (C) 1989, 1992-2019 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
80
# include "w32common.h"
Daniel Colascione's avatar
Daniel Colascione committed
81
# include "w32.h"
82 83
#endif

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

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

#define x_defined_color w32_defined_color
92

93 94
#endif /* HAVE_NTGUI */

95 96 97
#ifdef HAVE_NS
typedef struct ns_bitmap_record Bitmap_Record;

Juanma Barranquero's avatar
Juanma Barranquero committed
98
#define GET_PIXEL(ximg, x, y) XGetPixel (ximg, x, y)
99 100 101 102 103 104 105 106
#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 */

107 108 109 110 111 112
#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

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

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

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

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

152 153 154

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

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

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

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

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

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

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

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

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

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

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

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

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

248 249
  id = x_allocate_bitmap_record (f);

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

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

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

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

  if (!bitmap)
      return -1;


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

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

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

330
  filename = SSDATA (found);
331

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

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

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

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

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

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

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

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

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

  dpyinfo->bitmaps_last = 0;
}

411 412 413 414 415
#ifndef HAVE_XRENDER
/* Required for the definition of x_create_x_image_and_pixmap below.  */
typedef void Picture;
#endif

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

420 421 422 423 424 425 426 427 428 429 430 431 432 433
#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

434 435
#ifdef HAVE_X_WINDOWS

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

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

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


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

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

461
  Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
462 463

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

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

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

  if (!ximg)
    {
476
      unblock_input ();
477
      return;
478 479
    }

480 481
  result = x_create_x_image_and_pixmap (f, width, height, 1,
                                        &mask_img, &mask, NULL);
482

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

521
  dpyinfo->bitmaps[id - 1].have_mask = true;
522 523 524 525 526 527 528 529 530 531 532 533
  dpyinfo->bitmaps[id - 1].mask = mask;

  XDestroyImage (ximg);
  x_destroy_x_image (mask_img);
}

#endif /* HAVE_X_WINDOWS */

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

534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560
/* Each image format (JPEG, TIFF, ...) supported is described by
   a structure of the type below.  */

struct image_type
{
  /* Index of a symbol uniquely identifying the image type, e.g., 'jpeg'.  */
  int type;

  /* Check that SPEC is a valid image specification for the given
     image type.  Value is true if SPEC is valid.  */
  bool (*valid_p) (Lisp_Object spec);

  /* Load IMG which is used on frame F from information contained in
     IMG->spec.  Value is true if successful.  */
  bool (*load) (struct frame *f, struct image *img);

  /* Free resources of image IMG which is used on frame F.  */
  void (*free) (struct frame *f, struct image *img);

  /* Initialization function (used for dynamic loading of image
     libraries on Windows), or NULL if none.  */
  bool (*init) (void);

  /* Next in list of all supported image types.  */
  struct image_type *next;
};

561 562 563 564 565
/* 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;

566
/* Forward function prototypes.  */
567

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

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

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

Chong Yidong's avatar
Chong Yidong committed
586
static struct image_type *
587
define_image_type (struct image_type *type)
588
{
Chong Yidong's avatar
Chong Yidong committed
589
  struct image_type *p = NULL;
Paul Eggert's avatar
Paul Eggert committed
590 591
  int new_type = type->type;
  bool type_valid = true;
592

593
  block_input ();
Chong Yidong's avatar
Chong Yidong committed
594 595

  for (p = image_types; p; p = p->next)
596
    if (p->type == new_type)
Chong Yidong's avatar
Chong Yidong committed
597 598 599
      goto done;

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

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

Chong Yidong's avatar
Chong Yidong committed
626
 done:
627
  unblock_input ();
Chong Yidong's avatar
Chong Yidong committed
628
  return p;
629 630 631
}


632
/* Value is true if OBJECT is a valid Lisp image specification.  A
633 634 635 636 637 638
   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.  */

639
bool
640
valid_image_p (Lisp_Object object)
641
{
642
  bool valid_p = 0;
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

  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
668
/* Log error message with format string FORMAT and trailing arguments.
669 670 671 672 673 674
   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
675
image_error (const char *format, ...)
676
{
Paul Eggert's avatar
Paul Eggert committed
677 678 679 680
  va_list ap;
  va_start (ap, format);
  vadd_to_log (format, ap);
  va_end (ap);
681 682
}

683 684 685
static void
image_size_error (void)
{
686
  image_error ("Invalid image size (see `max-image-size')");
687
}
688 689 690 691 692 693 694 695 696 697 698 699 700


/***********************************************************************
			 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,
701
  IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR,
702 703 704 705 706 707 708 709 710 711 712 713 714
  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.  */
715
  const char *name;
716 717 718 719

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

720 721
  /* True means key must be present.  */
  bool mandatory_p;
722 723 724 725 726 727 728 729 730 731 732 733 734

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

737
static bool
738 739
parse_image_spec (Lisp_Object spec, struct image_keyword *keywords,
		  int nkeywords, Lisp_Object type)
740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765
{
  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)
766
	if (strcmp (keywords[i].name, SSDATA (SYMBOL_NAME (key))) == 0)
767 768 769 770 771 772 773 774 775 776
	  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;
777
      ++keywords[i].count;
778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797

      /* 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:
798
	  if (! RANGED_FIXNUMP (1, value, INT_MAX))
799 800 801
	    return 0;
	  break;

802
	case IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR:
803
	  if (RANGED_FIXNUMP (0, value, INT_MAX))
804 805
	    break;
	  if (CONSP (value)
806 807
	      && RANGED_FIXNUMP (0, XCAR (value), INT_MAX)
	      && RANGED_FIXNUMP (0, XCDR (value), INT_MAX))
808 809 810 811 812 813
	    break;
	  return 0;

	case IMAGE_ASCENT_VALUE:
	  if (SYMBOLP (value) && EQ (value, Qcenter))
	    break;
814
	  else if (RANGED_FIXNUMP (0, value, 100))
815 816 817 818
	    break;
	  return 0;

	case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
819 820 821
	  /* Unlike the other integer-related cases, this one does not
	     verify that VALUE fits in 'int'.  This is because callers
	     want EMACS_INT.  */
Tom Tromey's avatar
Tom Tromey committed
822
	  if (!FIXNUMP (value) || XFIXNUM (value) < 0)
823 824 825 826 827 828 829 830
	    return 0;
	  break;

	case IMAGE_DONT_CHECK_VALUE_TYPE:
	  break;

	case IMAGE_FUNCTION_VALUE:
	  value = indirect_function (value);
831
	  if (FUNCTIONP (value))
832 833 834 835
	    break;
	  return 0;

	case IMAGE_NUMBER_VALUE:
836
	  if (! NUMBERP (value))
837 838 839 840
	    return 0;
	  break;

	case IMAGE_INTEGER_VALUE:
841
	  if (! TYPE_RANGED_FIXNUMP (int, value))
842 843 844 845 846 847 848 849 850
	    return 0;
	  break;

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

	default:
851
	  emacs_abort ();
852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868
	  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
869 870
   if KEY is not present in SPEC.  Set *FOUND depending on whether KEY
   was found in SPEC.  */
871 872

static Lisp_Object
873
image_spec_value (Lisp_Object spec, Lisp_Object key, bool *found)
874 875 876
{
  Lisp_Object tail;

877
  eassert (valid_image_p (spec));
878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902

  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
903
  (Lisp_Object spec, Lisp_Object pixels, Lisp_Object frame)
904 905 906 907 908 909
{
  Lisp_Object size;

  size = Qnil;
  if (valid_image_p (spec))
    {
910
      struct frame *f = decode_window_system_frame (frame);
911
      ptrdiff_t id = lookup_image (f, spec);
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
920
	size = Fcons (make_fixnum (width), make_fixnum (height));
921 922 923 924 925 926 927 928 929 930 931 932
    }
  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
933
  (Lisp_Object spec, Lisp_Object frame)
934 935 936 937 938 939
{
  Lisp_Object mask;

  mask = Qnil;
  if (valid_image_p (spec))
    {
940
      struct frame *f = decode_window_system_frame (frame);
941
      ptrdiff_t id = lookup_image (f, spec);
942 943 944 945 946 947 948 949 950 951
      struct image *img = IMAGE_FROM_ID (f, id);
      if (img->mask)
	mask = Qt;
    }
  else
    error ("Invalid image specification");

  return mask;
}

952 953
DEFUN ("image-metadata", Fimage_metadata, Simage_metadata, 1, 2, 0,
       doc: /* Return metadata for image SPEC.
954 955
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
956
  (Lisp_Object spec, Lisp_Object frame)
957 958 959 960 961 962
{
  Lisp_Object ext;

  ext = Qnil;
  if (valid_image_p (spec))
    {
963
      struct frame *f = decode_window_system_frame (frame);
964
      ptrdiff_t id = lookup_image (f, spec);
965
      struct image *img = IMAGE_FROM_ID (f, id);
Chong Yidong's avatar
Chong Yidong committed
966
      ext = img->lisp_data;
967 968 969 970 971
    }

  return ext;
}

972 973 974 975 976

/***********************************************************************
		 Image type independent image structures
 ***********************************************************************/

977
#define MAX_IMAGE_SIZE 10.0
978 979 980 981
/* Allocate and return a new image structure for image specification
   SPEC.  SPEC has a hash value of HASH.  */

static struct image *
982
make_image (Lisp_Object spec, EMACS_UINT hash)
983
{
Dmitry Antipov's avatar
Dmitry Antipov committed
984
  struct image *img = xzalloc (sizeof *img);
985
  Lisp_Object file = image_spec_value (spec, QCfile, NULL);
986

987
  eassert (valid_image_p (spec));
988
  img->dependencies = NILP (file) ? Qnil : list1 (file);
989
  img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
990
  eassert (img->type != NULL);
991
  img->spec = spec;
Chong Yidong's avatar
Chong Yidong committed
992
  img->lisp_data = Qnil;
993 994
  img->ascent = DEFAULT_IMAGE_ASCENT;
  img->hash = hash;
995
  img->corners[BOT_CORNER] = -1;  /* Full image */
996 997 998 999 1000 1001 1002
  return img;
}


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

static void
1003
free_image (struct frame *f, struct image *img)
1004 1005 1006
{
  if (img)
    {
1007
      struct image_cache *c = FRAME_IMAGE_CACHE (f);
1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019

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

1020 1021 1022 1023 1024 1025 1026
#ifdef HAVE_XRENDER
      if (img->picture)
        XRenderFreePicture (FRAME_X_DISPLAY (f), img->picture);
      if (img->mask_picture)
        XRenderFreePicture (FRAME_X_DISPLAY (f), img->mask_picture);
#endif

1027 1028 1029 1030 1031
      /* Windows NT redefines 'free', but in this file, we need to
         avoid the redefinition.  */
#ifdef WINDOWSNT
#undef free
#endif
1032 1033 1034 1035 1036 1037
      /* Free resources, then free IMG.  */
      img->type->free (f, img);
      xfree (img);
    }
}

1038
/* Return true if the given widths and heights are valid for display.  */
1039

1040
static bool
1041
check_image_size (struct frame *f, int width, int height)
1042
{
1043
  int w, h;
1044

1045
  if (width <= 0 || height <= 0)
1046 1047
    return 0;

1048
  if (FIXNUMP (Vmax_image_size))
Tom Tromey's avatar
Tom Tromey committed
1049 1050
    return (width <= XFIXNUM (Vmax_image_size)
	    && height <= XFIXNUM (Vmax_image_size));
1051 1052
  else if (FLOATP (Vmax_image_size))
    {
1053 1054 1055 1056 1057 1058 1059
      if (f != NULL)
	{
	  w = FRAME_PIXEL_WIDTH (f);
	  h = FRAME_PIXEL_HEIGHT (f);
	}
      else
	w = h = 1024;  /* Arbitrary size for unknown frame. */
1060 1061
      return (width <= XFLOAT_DATA (Vmax_image_size) * w
	      && height <= XFLOAT_DATA (Vmax_image_size) * h);
1062 1063 1064
    }
  else
    return 1;
1065
}
1066 1067 1068 1069 1070

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

void
1071
prepare_image_for_display (struct frame *f, struct image *img)
1072 1073
{
  /* We're about to display IMG, so set its timestamp to `now'.  */
1074
  img->timestamp = current_timespec ();
1075

1076
#ifndef USE_CAIRO
1077 1078 1079
  /* 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)
1080
    img->load_failed_p = ! img->type->load (f, img);
1081

1082 1083 1084 1085 1086 1087 1088 1089
#ifdef HAVE_X_WINDOWS
  if (!img->load_failed_p)
    {
      block_input ();
      image_sync_to_pixmaps (f, img);
      unblock_input ();
    }
#endif
1090
#endif
1091 1092 1093 1094 1095 1096 1097
}


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

int
1098
image_ascent (struct image *img, struct face *face, struct glyph_slice *slice)
1099
{
1100
  int height;
1101 1102
  int ascent;

1103 1104