aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJuan José García-Ripoll2020-04-13 12:04:39 +0200
committerEli Zaretskii2020-04-14 09:52:55 +0300
commitdf254a7445a86dc25d133f2d79be8096190a8b96 (patch)
treec6094f663793c61f4243483c0c6d310205005a83
parent7a9fb5d55c9bf612a38348d59e769ee915175e28 (diff)
downloademacs-df254a7445a86dc25d133f2d79be8096190a8b96.tar.gz
emacs-df254a7445a86dc25d133f2d79be8096190a8b96.zip
Initial version of native image API support for MS-Windows
* src/w32image.c: New file. * src/w32term.h: Add prototypes of 'w32_load_image', 'w32_gdiplus_startup', 'w32_gdiplus_shutdown', and 'w32_query_frame_background_color'. * src/w32term.c (w32_query_frame_background_color): No longer static. * src/w32.c (term_ntproc) [HAVE_GDIPLUS]: Call 'w32_gdiplus_shutdown'. * src/image.c (struct image_type) <valid_p>: Accept an additional argument, the image type. All implementations changed. (init_native_image_functions, native_image_p, native_image_load) [HAVE_NATIVE_IMAGE_API]: New methods for "native image type". (initialize_image_type) [HAVE_NATIVE_IMAGE_API]: Call 'init_native_image_functions'. (image_types) [HAVE_NATIVE_IMAGE_API]: Add settings for native image API. (lookup_image_type) [HAVE_NATIVE_IMAGE_API]: Initialize native functions if needed. * lisp/term/w32-win.el (dynamic-library-alist): Add gdiplus and shlwapi. * etc/NEWS: Announce the new feature. * configure.ac (native-image-api): New option, OFF by default. (HAVE_NATIVE_IMAGE_API): If native-image-api is selected, add w32image.o to W32_OBJ.
-rw-r--r--configure.ac10
-rw-r--r--etc/NEWS7
-rw-r--r--lisp/term/w32-win.el2
-rw-r--r--src/image.c163
-rw-r--r--src/w32.c4
-rw-r--r--src/w32image.c306
-rw-r--r--src/w32term.c2
-rw-r--r--src/w32term.h7
8 files changed, 466 insertions, 35 deletions
diff --git a/configure.ac b/configure.ac
index 9907160482e..41a1860493a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -433,6 +433,7 @@ OPTION_DEFAULT_ON([libsystemd],[don't compile with libsystemd support])
433OPTION_DEFAULT_ON([cairo],[don't compile with Cairo drawing]) 433OPTION_DEFAULT_ON([cairo],[don't compile with Cairo drawing])
434OPTION_DEFAULT_ON([xml2],[don't compile with XML parsing support]) 434OPTION_DEFAULT_ON([xml2],[don't compile with XML parsing support])
435OPTION_DEFAULT_OFF([imagemagick],[compile with ImageMagick image support]) 435OPTION_DEFAULT_OFF([imagemagick],[compile with ImageMagick image support])
436OPTION_DEFAULT_OFF([native-image-api], [use native API's (GDI+ on Windows) for JPEG/TIFF/GIFF/PNG])
436OPTION_DEFAULT_ON([json], [don't compile with native JSON support]) 437OPTION_DEFAULT_ON([json], [don't compile with native JSON support])
437 438
438OPTION_DEFAULT_ON([xft],[don't use XFT for anti aliased fonts]) 439OPTION_DEFAULT_ON([xft],[don't use XFT for anti aliased fonts])
@@ -2126,6 +2127,7 @@ LIB_WSOCK32=
2126NTLIB= 2127NTLIB=
2127CM_OBJ="cm.o" 2128CM_OBJ="cm.o"
2128XARGS_LIMIT= 2129XARGS_LIMIT=
2130HAVE_NATIVE_IMAGE_API=no
2129if test "${HAVE_W32}" = "yes"; then 2131if test "${HAVE_W32}" = "yes"; then
2130 AC_DEFINE(HAVE_NTGUI, 1, [Define to use native MS Windows GUI.]) 2132 AC_DEFINE(HAVE_NTGUI, 1, [Define to use native MS Windows GUI.])
2131 if test "$with_toolkit_scroll_bars" = "no"; then 2133 if test "$with_toolkit_scroll_bars" = "no"; then
@@ -2154,7 +2156,12 @@ if test "${HAVE_W32}" = "yes"; then
2154 # the rc file), not a linker script. 2156 # the rc file), not a linker script.
2155 W32_RES_LINK="-Wl,emacs.res" 2157 W32_RES_LINK="-Wl,emacs.res"
2156 else 2158 else
2157 W32_OBJ="$W32_OBJ w32.o w32console.o w32heap.o w32inevt.o w32proc.o" 2159 if test "${with_native_image_api}" = yes; then
2160 AC_DEFINE(HAVE_NATIVE_IMAGE_API, 1, [Define to use MS Windows GDI+ for images.])
2161 HAVE_NATIVE_IMAGE_API=yes
2162 W32_NATIVE_IMAGE_API="w32image.o"
2163 fi
2164 W32_OBJ="$W32_OBJ w32.o w32console.o w32heap.o w32inevt.o w32proc.o $W32_NATIVE_IMAGE_API"
2158 W32_LIBS="$W32_LIBS -lwinmm -lusp10 -lgdi32 -lcomdlg32" 2165 W32_LIBS="$W32_LIBS -lwinmm -lusp10 -lgdi32 -lcomdlg32"
2159 W32_LIBS="$W32_LIBS -lmpr -lwinspool -lole32 -lcomctl32" 2166 W32_LIBS="$W32_LIBS -lmpr -lwinspool -lole32 -lcomctl32"
2160 W32_RES_LINK="\$(EMACSRES)" 2167 W32_RES_LINK="\$(EMACSRES)"
@@ -5703,6 +5710,7 @@ AS_ECHO([" Does Emacs use -lXaw3d? ${HAVE_XAW3D
5703 Does Emacs use cairo? ${HAVE_CAIRO} 5710 Does Emacs use cairo? ${HAVE_CAIRO}
5704 Does Emacs use -llcms2? ${HAVE_LCMS2} 5711 Does Emacs use -llcms2? ${HAVE_LCMS2}
5705 Does Emacs use imagemagick? ${HAVE_IMAGEMAGICK} 5712 Does Emacs use imagemagick? ${HAVE_IMAGEMAGICK}
5713 Does Emacs use native API for images? ${HAVE_NATIVE_IMAGE_API}
5706 Does Emacs support sound? ${HAVE_SOUND} 5714 Does Emacs support sound? ${HAVE_SOUND}
5707 Does Emacs use -lgpm? ${HAVE_GPM} 5715 Does Emacs use -lgpm? ${HAVE_GPM}
5708 Does Emacs use -ldbus? ${HAVE_DBUS} 5716 Does Emacs use -ldbus? ${HAVE_DBUS}
diff --git a/etc/NEWS b/etc/NEWS
index 46f59ab869f..7ed24e3f85b 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -386,6 +386,13 @@ and enable the MS-Windows native Input Method Editor (IME) at run
386time. A companion function 'w32-get-ime-open-status' returns the 386time. A companion function 'w32-get-ime-open-status' returns the
387current IME activation status. 387current IME activation status.
388 388
389+++
390** On MS-Windows, Emacs can now use the native image API to display images.
391Emacs can now use the MS-Windows GDI+ library to load and display
392images in JPEG, PNG, GIF and TIFF formats. This support is enabled
393with --with-native-image-api, which automatically disables the use of
394optional third party libraries for those formats.
395
389 396
390---------------------------------------------------------------------- 397----------------------------------------------------------------------
391This file is part of GNU Emacs. 398This file is part of GNU Emacs.
diff --git a/lisp/term/w32-win.el b/lisp/term/w32-win.el
index 3e932c7593d..5901e0295e1 100644
--- a/lisp/term/w32-win.el
+++ b/lisp/term/w32-win.el
@@ -231,6 +231,8 @@ See the documentation of `create-fontset-from-fontset-spec' for the format.")
231;;; Set default known names for external libraries 231;;; Set default known names for external libraries
232(setq dynamic-library-alist 232(setq dynamic-library-alist
233 (list 233 (list
234 '(gdiplus "gdiplus.dll")
235 '(shlwapi "shlwapi.dll")
234 '(xpm "libxpm.dll" "xpm4.dll" "libXpm-nox4.dll") 236 '(xpm "libxpm.dll" "xpm4.dll" "libXpm-nox4.dll")
235 ;; Versions of libpng 1.4.x and later are incompatible with 237 ;; Versions of libpng 1.4.x and later are incompatible with
236 ;; earlier versions. Set up the list of libraries according to 238 ;; earlier versions. Set up the list of libraries according to
diff --git a/src/image.c b/src/image.c
index c98ca291ca5..ff2d12fa1a1 100644
--- a/src/image.c
+++ b/src/image.c
@@ -751,7 +751,7 @@ struct image_type
751 751
752 /* Check that SPEC is a valid image specification for the given 752 /* Check that SPEC is a valid image specification for the given
753 image type. Value is true if SPEC is valid. */ 753 image type. Value is true if SPEC is valid. */
754 bool (*valid_p) (Lisp_Object spec); 754 bool (*valid_p) (Lisp_Object spec, Lisp_Object type);
755 755
756 /* Load IMG which is used on frame F from information contained in 756 /* Load IMG which is used on frame F from information contained in
757 IMG->spec. Value is true if successful. */ 757 IMG->spec. Value is true if successful. */
@@ -807,7 +807,7 @@ valid_image_p (Lisp_Object object)
807 { 807 {
808 struct image_type const *type = lookup_image_type (XCAR (tail)); 808 struct image_type const *type = lookup_image_type (XCAR (tail));
809 if (type) 809 if (type)
810 return type->valid_p (object); 810 return type->valid_p (object, builtin_lisp_symbol (type->type));
811 } 811 }
812 break; 812 break;
813 } 813 }
@@ -3144,12 +3144,12 @@ enum xbm_token
3144 displayed is used. */ 3144 displayed is used. */
3145 3145
3146static bool 3146static bool
3147xbm_image_p (Lisp_Object object) 3147xbm_image_p (Lisp_Object object, Lisp_Object type)
3148{ 3148{
3149 struct image_keyword kw[XBM_LAST]; 3149 struct image_keyword kw[XBM_LAST];
3150 3150
3151 memcpy (kw, xbm_format, sizeof kw); 3151 memcpy (kw, xbm_format, sizeof kw);
3152 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm)) 3152 if (!parse_image_spec (object, kw, XBM_LAST, type))
3153 return 0; 3153 return 0;
3154 3154
3155 eassert (EQ (kw[XBM_TYPE].value, Qxbm)); 3155 eassert (EQ (kw[XBM_TYPE].value, Qxbm));
@@ -3697,7 +3697,7 @@ xbm_load (struct frame *f, struct image *img)
3697 bool success_p = 0; 3697 bool success_p = 0;
3698 Lisp_Object file_name; 3698 Lisp_Object file_name;
3699 3699
3700 eassert (xbm_image_p (img->spec)); 3700 eassert (xbm_image_p (img->spec, Qxbm));
3701 3701
3702 /* If IMG->spec specifies a file name, create a non-file spec from it. */ 3702 /* If IMG->spec specifies a file name, create a non-file spec from it. */
3703 file_name = image_spec_value (img->spec, QCfile, NULL); 3703 file_name = image_spec_value (img->spec, QCfile, NULL);
@@ -4155,11 +4155,11 @@ xpm_valid_color_symbols_p (Lisp_Object color_symbols)
4155/* Value is true if OBJECT is a valid XPM image specification. */ 4155/* Value is true if OBJECT is a valid XPM image specification. */
4156 4156
4157static bool 4157static bool
4158xpm_image_p (Lisp_Object object) 4158xpm_image_p (Lisp_Object object, Lisp_Object type)
4159{ 4159{
4160 struct image_keyword fmt[XPM_LAST]; 4160 struct image_keyword fmt[XPM_LAST];
4161 memcpy (fmt, xpm_format, sizeof fmt); 4161 memcpy (fmt, xpm_format, sizeof fmt);
4162 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm) 4162 return (parse_image_spec (object, fmt, XPM_LAST, type)
4163 /* Either `:file' or `:data' must be present. */ 4163 /* Either `:file' or `:data' must be present. */
4164 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1 4164 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
4165 /* Either no `:color-symbols' or it's a list of conses 4165 /* Either no `:color-symbols' or it's a list of conses
@@ -5883,13 +5883,13 @@ static const struct image_keyword pbm_format[PBM_LAST] =
5883/* Return true if OBJECT is a valid PBM image specification. */ 5883/* Return true if OBJECT is a valid PBM image specification. */
5884 5884
5885static bool 5885static bool
5886pbm_image_p (Lisp_Object object) 5886pbm_image_p (Lisp_Object object, Lisp_Object type)
5887{ 5887{
5888 struct image_keyword fmt[PBM_LAST]; 5888 struct image_keyword fmt[PBM_LAST];
5889 5889
5890 memcpy (fmt, pbm_format, sizeof fmt); 5890 memcpy (fmt, pbm_format, sizeof fmt);
5891 5891
5892 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)) 5892 if (!parse_image_spec (object, fmt, PBM_LAST, type))
5893 return 0; 5893 return 0;
5894 5894
5895 /* Must specify either :data or :file. */ 5895 /* Must specify either :data or :file. */
@@ -6233,6 +6233,83 @@ pbm_load (struct frame *f, struct image *img)
6233 6233
6234 6234
6235/*********************************************************************** 6235/***********************************************************************
6236 NATIVE IMAGE HANDLING
6237 ***********************************************************************/
6238#if defined(HAVE_NATIVE_IMAGE_API) && defined(HAVE_NTGUI)
6239/*
6240 * These functions are actually defined in the OS-native implementation
6241 * file. Currently, for Windows GDI+ interface, w32image.c, but other
6242 * operating systems can follow suit.
6243 */
6244
6245static bool
6246init_native_image_functions (void)
6247{
6248 return w32_gdiplus_startup ();
6249}
6250
6251/* Indices of image specification fields in native format, below. */
6252
6253enum native_image_keyword_index
6254{
6255 NATIVE_IMAGE_TYPE,
6256 NATIVE_IMAGE_DATA,
6257 NATIVE_IMAGE_FILE,
6258 NATIVE_IMAGE_ASCENT,
6259 NATIVE_IMAGE_MARGIN,
6260 NATIVE_IMAGE_RELIEF,
6261 NATIVE_IMAGE_ALGORITHM,
6262 NATIVE_IMAGE_HEURISTIC_MASK,
6263 NATIVE_IMAGE_MASK,
6264 NATIVE_IMAGE_BACKGROUND,
6265 NATIVE_IMAGE_INDEX,
6266 NATIVE_IMAGE_LAST
6267};
6268
6269/* Vector of image_keyword structures describing the format
6270 of valid user-defined image specifications. */
6271
6272static const struct image_keyword native_image_format[] =
6273{
6274 {":type", IMAGE_SYMBOL_VALUE, 1},
6275 {":data", IMAGE_STRING_VALUE, 0},
6276 {":file", IMAGE_STRING_VALUE, 0},
6277 {":ascent", IMAGE_ASCENT_VALUE, 0},
6278 {":margin", IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR, 0},
6279 {":relief", IMAGE_INTEGER_VALUE, 0},
6280 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6281 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6282 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6283 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
6284 {":index", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}
6285};
6286
6287/* Return true if OBJECT is a valid native API image specification. */
6288
6289static bool
6290native_image_p (Lisp_Object object, Lisp_Object type)
6291{
6292 struct image_keyword fmt[NATIVE_IMAGE_LAST];
6293 memcpy (fmt, native_image_format, sizeof fmt);
6294
6295 if (!parse_image_spec (object, fmt, 10, type))
6296 return 0;
6297
6298 /* Must specify either the :data or :file keyword. */
6299 return fmt[NATIVE_IMAGE_FILE].count + fmt[NATIVE_IMAGE_DATA].count == 1;
6300}
6301
6302static bool
6303native_image_load (struct frame *f, struct image *img)
6304{
6305 return w32_load_image (f, img,
6306 image_spec_value (img->spec, QCfile, NULL),
6307 image_spec_value (img->spec, QCdata, NULL));
6308}
6309#endif
6310
6311
6312/***********************************************************************
6236 PNG 6313 PNG
6237 ***********************************************************************/ 6314 ***********************************************************************/
6238 6315
@@ -6275,12 +6352,12 @@ static const struct image_keyword png_format[PNG_LAST] =
6275/* Return true if OBJECT is a valid PNG image specification. */ 6352/* Return true if OBJECT is a valid PNG image specification. */
6276 6353
6277static bool 6354static bool
6278png_image_p (Lisp_Object object) 6355png_image_p (Lisp_Object object, Lisp_Object type)
6279{ 6356{
6280 struct image_keyword fmt[PNG_LAST]; 6357 struct image_keyword fmt[PNG_LAST];
6281 memcpy (fmt, png_format, sizeof fmt); 6358 memcpy (fmt, png_format, sizeof fmt);
6282 6359
6283 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)) 6360 if (!parse_image_spec (object, fmt, PNG_LAST, type))
6284 return 0; 6361 return 0;
6285 6362
6286 /* Must specify either the :data or :file keyword. */ 6363 /* Must specify either the :data or :file keyword. */
@@ -6890,7 +6967,6 @@ png_load (struct frame *f, struct image *img)
6890 image_spec_value (img->spec, QCdata, NULL)); 6967 image_spec_value (img->spec, QCdata, NULL));
6891} 6968}
6892 6969
6893
6894#endif /* HAVE_NS */ 6970#endif /* HAVE_NS */
6895 6971
6896 6972
@@ -6938,13 +7014,13 @@ static const struct image_keyword jpeg_format[JPEG_LAST] =
6938/* Return true if OBJECT is a valid JPEG image specification. */ 7014/* Return true if OBJECT is a valid JPEG image specification. */
6939 7015
6940static bool 7016static bool
6941jpeg_image_p (Lisp_Object object) 7017jpeg_image_p (Lisp_Object object, Lisp_Object type)
6942{ 7018{
6943 struct image_keyword fmt[JPEG_LAST]; 7019 struct image_keyword fmt[JPEG_LAST];
6944 7020
6945 memcpy (fmt, jpeg_format, sizeof fmt); 7021 memcpy (fmt, jpeg_format, sizeof fmt);
6946 7022
6947 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)) 7023 if (!parse_image_spec (object, fmt, JPEG_LAST, type))
6948 return 0; 7024 return 0;
6949 7025
6950 /* Must specify either the :data or :file keyword. */ 7026 /* Must specify either the :data or :file keyword. */
@@ -7514,12 +7590,12 @@ static const struct image_keyword tiff_format[TIFF_LAST] =
7514/* Return true if OBJECT is a valid TIFF image specification. */ 7590/* Return true if OBJECT is a valid TIFF image specification. */
7515 7591
7516static bool 7592static bool
7517tiff_image_p (Lisp_Object object) 7593tiff_image_p (Lisp_Object object, Lisp_Object type)
7518{ 7594{
7519 struct image_keyword fmt[TIFF_LAST]; 7595 struct image_keyword fmt[TIFF_LAST];
7520 memcpy (fmt, tiff_format, sizeof fmt); 7596 memcpy (fmt, tiff_format, sizeof fmt);
7521 7597
7522 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)) 7598 if (!parse_image_spec (object, fmt, TIFF_LAST, type))
7523 return 0; 7599 return 0;
7524 7600
7525 /* Must specify either the :data or :file keyword. */ 7601 /* Must specify either the :data or :file keyword. */
@@ -7962,19 +8038,19 @@ gif_clear_image (struct frame *f, struct image *img)
7962/* Return true if OBJECT is a valid GIF image specification. */ 8038/* Return true if OBJECT is a valid GIF image specification. */
7963 8039
7964static bool 8040static bool
7965gif_image_p (Lisp_Object object) 8041gif_image_p (Lisp_Object object, Lisp_Object type)
7966{ 8042{
7967 struct image_keyword fmt[GIF_LAST]; 8043 struct image_keyword fmt[GIF_LAST];
7968 memcpy (fmt, gif_format, sizeof fmt); 8044 memcpy (fmt, gif_format, sizeof fmt);
7969 8045
7970 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)) 8046 if (!parse_image_spec (object, fmt, GIF_LAST, type))
7971 return 0; 8047 return 0;
7972 8048
7973 /* Must specify either the :data or :file keyword. */ 8049 /* Must specify either the :data or :file keyword. */
7974 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1; 8050 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
7975} 8051}
7976 8052
7977#endif /* HAVE_GIF */ 8053#endif /* HAVE_GIF || HAVE_NS */
7978 8054
7979#ifdef HAVE_GIF 8055#ifdef HAVE_GIF
7980 8056
@@ -8574,12 +8650,12 @@ imagemagick_clear_image (struct frame *f,
8574 identify the IMAGEMAGICK format. */ 8650 identify the IMAGEMAGICK format. */
8575 8651
8576static bool 8652static bool
8577imagemagick_image_p (Lisp_Object object) 8653imagemagick_image_p (Lisp_Object object, Lisp_Object type)
8578{ 8654{
8579 struct image_keyword fmt[IMAGEMAGICK_LAST]; 8655 struct image_keyword fmt[IMAGEMAGICK_LAST];
8580 memcpy (fmt, imagemagick_format, sizeof fmt); 8656 memcpy (fmt, imagemagick_format, sizeof fmt);
8581 8657
8582 if (!parse_image_spec (object, fmt, IMAGEMAGICK_LAST, Qimagemagick)) 8658 if (!parse_image_spec (object, fmt, IMAGEMAGICK_LAST, type))
8583 return 0; 8659 return 0;
8584 8660
8585 /* Must specify either the :data or :file keyword. */ 8661 /* Must specify either the :data or :file keyword. */
@@ -9369,12 +9445,12 @@ static const struct image_keyword svg_format[SVG_LAST] =
9369 identify the SVG format. */ 9445 identify the SVG format. */
9370 9446
9371static bool 9447static bool
9372svg_image_p (Lisp_Object object) 9448svg_image_p (Lisp_Object object, Lisp_Object type)
9373{ 9449{
9374 struct image_keyword fmt[SVG_LAST]; 9450 struct image_keyword fmt[SVG_LAST];
9375 memcpy (fmt, svg_format, sizeof fmt); 9451 memcpy (fmt, svg_format, sizeof fmt);
9376 9452
9377 if (!parse_image_spec (object, fmt, SVG_LAST, Qsvg)) 9453 if (!parse_image_spec (object, fmt, SVG_LAST, type))
9378 return 0; 9454 return 0;
9379 9455
9380 /* Must specify either the :data or :file keyword. */ 9456 /* Must specify either the :data or :file keyword. */
@@ -9837,7 +9913,7 @@ static const struct image_keyword gs_format[GS_LAST] =
9837 specification. */ 9913 specification. */
9838 9914
9839static bool 9915static bool
9840gs_image_p (Lisp_Object object) 9916gs_image_p (Lisp_Object object, Lisp_Object type)
9841{ 9917{
9842 struct image_keyword fmt[GS_LAST]; 9918 struct image_keyword fmt[GS_LAST];
9843 Lisp_Object tem; 9919 Lisp_Object tem;
@@ -9845,7 +9921,7 @@ gs_image_p (Lisp_Object object)
9845 9921
9846 memcpy (fmt, gs_format, sizeof fmt); 9922 memcpy (fmt, gs_format, sizeof fmt);
9847 9923
9848 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)) 9924 if (!parse_image_spec (object, fmt, GS_LAST, type))
9849 return 0; 9925 return 0;
9850 9926
9851 /* Bounding box must be a list or vector containing 4 integers. */ 9927 /* Bounding box must be a list or vector containing 4 integers. */
@@ -10132,13 +10208,20 @@ static bool
10132initialize_image_type (struct image_type const *type) 10208initialize_image_type (struct image_type const *type)
10133{ 10209{
10134#ifdef WINDOWSNT 10210#ifdef WINDOWSNT
10135 Lisp_Object typesym = builtin_lisp_symbol (type->type); 10211 Lisp_Object typesym, tested;
10136 Lisp_Object tested = Fassq (typesym, Vlibrary_cache); 10212 bool (*init) (void) = type->init;
10213
10214#ifdef HAVE_NATIVE_IMAGE_API
10215 if (init == init_native_image_functions)
10216 return init();
10217#endif
10218
10219 typesym = builtin_lisp_symbol (type->type);
10220 tested = Fassq (typesym, Vlibrary_cache);
10137 /* If we failed to load the library before, don't try again. */ 10221 /* If we failed to load the library before, don't try again. */
10138 if (CONSP (tested)) 10222 if (CONSP (tested))
10139 return !NILP (XCDR (tested)) ? true : false; 10223 return !NILP (XCDR (tested)) ? true : false;
10140 10224
10141 bool (*init) (void) = type->init;
10142 if (init) 10225 if (init)
10143 { 10226 {
10144 bool type_valid = init (); 10227 bool type_valid = init ();
@@ -10165,6 +10248,16 @@ static struct image_type const image_types[] =
10165 { SYMBOL_INDEX (Qsvg), svg_image_p, svg_load, image_clear_image, 10248 { SYMBOL_INDEX (Qsvg), svg_image_p, svg_load, image_clear_image,
10166 IMAGE_TYPE_INIT (init_svg_functions) }, 10249 IMAGE_TYPE_INIT (init_svg_functions) },
10167#endif 10250#endif
10251#if defined HAVE_NATIVE_IMAGE_API
10252 { SYMBOL_INDEX (Qjpeg), native_image_p, native_image_load, image_clear_image,
10253 IMAGE_TYPE_INIT (init_native_image_functions) },
10254 { SYMBOL_INDEX (Qpng), native_image_p, native_image_load, image_clear_image,
10255 IMAGE_TYPE_INIT (init_native_image_functions) },
10256 { SYMBOL_INDEX (Qgif), native_image_p, native_image_load, image_clear_image,
10257 IMAGE_TYPE_INIT (init_native_image_functions) },
10258 { SYMBOL_INDEX (Qtiff), native_image_p, native_image_load, image_clear_image,
10259 IMAGE_TYPE_INIT (init_native_image_functions) },
10260#endif
10168#if defined HAVE_PNG || defined HAVE_NS 10261#if defined HAVE_PNG || defined HAVE_NS
10169 { SYMBOL_INDEX (Qpng), png_image_p, png_load, image_clear_image, 10262 { SYMBOL_INDEX (Qpng), png_image_p, png_load, image_clear_image,
10170 IMAGE_TYPE_INIT (init_png_functions) }, 10263 IMAGE_TYPE_INIT (init_png_functions) },
@@ -10199,7 +10292,13 @@ lookup_image_type (Lisp_Object type)
10199 { 10292 {
10200 struct image_type const *r = &image_types[i]; 10293 struct image_type const *r = &image_types[i];
10201 if (EQ (type, builtin_lisp_symbol (r->type))) 10294 if (EQ (type, builtin_lisp_symbol (r->type)))
10295#ifdef HAVE_NATIVE_IMAGE_API
10296 /* We can have more than one backend for one image type. */
10297 if (initialize_image_type (r))
10298 return r;
10299#else
10202 return initialize_image_type (r) ? r : NULL; 10300 return initialize_image_type (r) ? r : NULL;
10301#endif
10203 } 10302 }
10204 return NULL; 10303 return NULL;
10205} 10304}
@@ -10316,22 +10415,22 @@ non-numeric, there is no explicit limit on the size of images. */);
10316 add_image_type (Qxpm); 10415 add_image_type (Qxpm);
10317#endif 10416#endif
10318 10417
10319#if defined (HAVE_JPEG) || defined (HAVE_NS) 10418#if defined (HAVE_JPEG) || defined (HAVE_NS) || defined (HAVE_NATIVE_IMAGE_API)
10320 DEFSYM (Qjpeg, "jpeg"); 10419 DEFSYM (Qjpeg, "jpeg");
10321 add_image_type (Qjpeg); 10420 add_image_type (Qjpeg);
10322#endif 10421#endif
10323 10422
10324#if defined (HAVE_TIFF) || defined (HAVE_NS) 10423#if defined (HAVE_TIFF) || defined (HAVE_NS) || defined (HAVE_NATIVE_IMAGE_API)
10325 DEFSYM (Qtiff, "tiff"); 10424 DEFSYM (Qtiff, "tiff");
10326 add_image_type (Qtiff); 10425 add_image_type (Qtiff);
10327#endif 10426#endif
10328 10427
10329#if defined (HAVE_GIF) || defined (HAVE_NS) 10428#if defined (HAVE_GIF) || defined (HAVE_NS) || defined (HAVE_NATIVE_IMAGE_API)
10330 DEFSYM (Qgif, "gif"); 10429 DEFSYM (Qgif, "gif");
10331 add_image_type (Qgif); 10430 add_image_type (Qgif);
10332#endif 10431#endif
10333 10432
10334#if defined (HAVE_PNG) || defined (HAVE_NS) 10433#if defined (HAVE_PNG) || defined (HAVE_NS) || defined(HAVE_NATIVE_IMAGE_API)
10335 DEFSYM (Qpng, "png"); 10434 DEFSYM (Qpng, "png");
10336 add_image_type (Qpng); 10435 add_image_type (Qpng);
10337#endif 10436#endif
diff --git a/src/w32.c b/src/w32.c
index 698e10e234e..1d2a52b6df4 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -10225,6 +10225,10 @@ term_ntproc (int ignored)
10225 term_winsock (); 10225 term_winsock ();
10226 10226
10227 term_w32select (); 10227 term_w32select ();
10228
10229#ifdef HAVE_GDIPLUS
10230 w32_gdiplus_shutdown ();
10231#endif
10228} 10232}
10229 10233
10230void 10234void
diff --git a/src/w32image.c b/src/w32image.c
new file mode 100644
index 00000000000..fe32660f712
--- /dev/null
+++ b/src/w32image.c
@@ -0,0 +1,306 @@
1/* Implementation of MS-Windows native image API via the GDI+ library.
2
3Copyright (C) 2020 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20/* Written by Juan Jose Garcia-Ripoll <juanjose.garciaripoll@gmail.com>. */
21
22#include <config.h>
23#include "lisp.h"
24#include "dispextern.h"
25#define COBJMACROS
26#include <objidl.h>
27#include <wtypes.h>
28#include <gdiplus.h>
29#include <shlwapi.h>
30#include "w32common.h"
31#include "w32term.h"
32#include "frame.h"
33#include "coding.h"
34
35/*#define LINK_GDIPLUS_STATICALLY 1*/
36
37#ifndef LINK_GDIPLUS_STATICALLY
38DEF_DLL_FN (GpStatus, GdiplusStartup, (ULONG_PTR *, GdiplusStartupInput *, GdiplusStartupOutput *));
39DEF_DLL_FN (VOID, GdiplusShutdown, (ULONG_PTR));
40DEF_DLL_FN (GpStatus, GdipGetPropertyItemSize, (GpImage *, PROPID, UINT *));
41DEF_DLL_FN (GpStatus, GdipGetPropertyItem, (GpImage *, PROPID, UINT, PropertyItem *));
42DEF_DLL_FN (GpStatus, GdipImageGetFrameDimensionsCount, (GpImage *, UINT *));
43DEF_DLL_FN (GpStatus, GdipImageGetFrameDimensionsList, (GpImage *, GUID *, UINT));
44DEF_DLL_FN (GpStatus, GdipImageGetFrameCount, (GpImage *, GDIPCONST GUID *, UINT *));
45DEF_DLL_FN (GpStatus, GdipImageSelectActiveFrame, (GpImage*, GDIPCONST GUID *, UINT));
46DEF_DLL_FN (GpStatus, GdipCreateBitmapFromFile, (WCHAR *, GpBitmap **));
47DEF_DLL_FN (GpStatus, GdipCreateBitmapFromStream, (IStream *, GpBitmap **));
48DEF_DLL_FN (IStream *, SHCreateMemStream, (const BYTE *pInit, UINT cbInit));
49DEF_DLL_FN (GpStatus, GdipCreateHBITMAPFromBitmap, (GpBitmap *, HBITMAP *, ARGB));
50DEF_DLL_FN (GpStatus, GdipDisposeImage, (GpImage *));
51DEF_DLL_FN (GpStatus, GdipGetImageHeight, (GpImage *, UINT *));
52DEF_DLL_FN (GpStatus, GdipGetImageWidth, (GpImage *, UINT *));
53#endif
54
55static int gdip_initialized = 0;
56static ULONG_PTR token;
57static GdiplusStartupInput input;
58static GdiplusStartupOutput output;
59
60bool
61w32_gdiplus_startup (void)
62{
63 HANDLE gdiplus_lib, shlwapi_lib;
64 GpStatus status;
65
66 if (gdip_initialized < 0)
67 return 0;
68 else if (gdip_initialized)
69 return 1;
70
71#ifndef LINK_GDIPLUS_STATICALLY
72 DEFSYM (Qgdiplus, "gdiplus");
73 DEFSYM (Qshlwapi, "shlwapi");
74 if (!(gdiplus_lib = w32_delayed_load (Qgdiplus))) {
75 gdip_initialized = -1;
76 return 0;
77 }
78 if (!(shlwapi_lib = w32_delayed_load (Qshlwapi))) {
79 gdip_initialized = -1;
80 return 0;
81 }
82
83 LOAD_DLL_FN (gdiplus_lib, GdiplusStartup);
84 LOAD_DLL_FN (gdiplus_lib, GdiplusShutdown);
85 LOAD_DLL_FN (gdiplus_lib, GdipGetPropertyItemSize);
86 LOAD_DLL_FN (gdiplus_lib, GdipGetPropertyItem);
87 LOAD_DLL_FN (gdiplus_lib, GdipImageGetFrameDimensionsCount);
88 LOAD_DLL_FN (gdiplus_lib, GdipImageGetFrameDimensionsList);
89 LOAD_DLL_FN (gdiplus_lib, GdipImageGetFrameCount);
90 LOAD_DLL_FN (gdiplus_lib, GdipImageSelectActiveFrame);
91 LOAD_DLL_FN (gdiplus_lib, GdipCreateBitmapFromFile);
92 LOAD_DLL_FN (gdiplus_lib, GdipCreateBitmapFromStream);
93 LOAD_DLL_FN (gdiplus_lib, GdipCreateHBITMAPFromBitmap);
94 LOAD_DLL_FN (gdiplus_lib, GdipDisposeImage);
95 LOAD_DLL_FN (gdiplus_lib, GdipGetImageHeight);
96 LOAD_DLL_FN (gdiplus_lib, GdipGetImageWidth);
97 LOAD_DLL_FN (shlwapi_lib, SHCreateMemStream);
98
99# define GdiplusStartup fn_GdiplusStartup
100# define GdiplusShutdown fn_GdiplusShutdown
101# define GdipGetPropertyItemSize fn_GdipGetPropertyItemSize
102# define GdipGetPropertyItem fn_GdipGetPropertyItem
103# define GdipImageGetFrameDimensionsCount fn_GdipImageGetFrameDimensionsCount
104# define GdipImageGetFrameDimensionsList fn_GdipImageGetFrameDimensionsList
105# define GdipImageGetFrameCount fn_GdipImageGetFrameCount
106# define GdipImageSelectActiveFrame fn_GdipImageSelectActiveFrame
107# define GdipCreateBitmapFromFile fn_GdipCreateBitmapFromFile
108# define GdipCreateBitmapFromStream fn_GdipCreateBitmapFromStream
109# define SHCreateMemStream fn_SHCreateMemStream
110# define GdipCreateHBITMAPFromBitmap fn_GdipCreateHBITMAPFromBitmap
111# define GdipDisposeImage fn_GdipDisposeImage
112# define GdipGetImageHeight fn_GdipGetImageHeight
113# define GdipGetImageWidth fn_GdipGetImageWidth
114#endif
115
116 input.GdiplusVersion = 1;
117 input.DebugEventCallback = NULL;
118 input.SuppressBackgroundThread = FALSE;
119 input.SuppressExternalCodecs = FALSE;
120
121 status = GdiplusStartup (&token, &input, &output);
122 if (status == Ok)
123 {
124 gdip_initialized = 1;
125 return 1;
126 }
127 else
128 {
129 gdip_initialized = -1;
130 return 0;
131 }
132}
133
134void
135w32_gdiplus_shutdown (void)
136{
137 GdiplusShutdown (token);
138}
139
140
141static double
142w32_frame_delay (GpBitmap *pBitmap, int frame)
143{
144 UINT size;
145 PropertyItem *propertyItem;
146 double delay = 0.0;
147
148 /* Assume that the image has a property item of type PropertyItemEquipMake.
149 Get the size of that property item. */
150 GdipGetPropertyItemSize (pBitmap, PropertyTagFrameDelay, &size);
151
152 /* Allocate a buffer to receive the property item. */
153 propertyItem = (PropertyItem*)malloc (size);
154 if (propertyItem != NULL)
155 {
156 /* Get the property item. */
157 GdipGetPropertyItem (pBitmap, PropertyTagFrameDelay, size, propertyItem);
158 delay = ((double)propertyItem[frame].length) / 100;
159 if (delay == 0)
160 {
161 /* In GIF files, unfortunately, delay is only specified for the first
162 frame. */
163 delay = ((double)propertyItem[0].length) / 100;
164 }
165 free (propertyItem);
166 }
167 return delay;
168}
169
170static UINT
171w32_select_active_frame (GpBitmap *pBitmap, int frame, int *nframes, double *delay)
172{
173 UINT count, frameCount;
174 GUID pDimensionIDs[1];
175 GpStatus status = Ok;
176
177 status = GdipImageGetFrameDimensionsCount (pBitmap, &count);
178 frameCount = *nframes = 0;
179 *delay = 0.0;
180 if (count)
181 {
182 status = GdipImageGetFrameDimensionsList (pBitmap, pDimensionIDs, 1);
183 status = GdipImageGetFrameCount (pBitmap, &pDimensionIDs[0], &frameCount);
184 if ((status == Ok) && (frameCount > 1))
185 {
186 if (frame < 0 || frame >= frameCount)
187 {
188 status = GenericError;
189 }
190 else
191 {
192 status = GdipImageSelectActiveFrame (pBitmap, &pDimensionIDs[0], frame);
193 *delay = w32_frame_delay (pBitmap, frame);
194 *nframes = frameCount;
195 }
196 }
197 }
198 return status;
199}
200
201static ARGB
202w32_image_bg_color (struct frame *f, struct image *img)
203{
204 /* png_color_16 *image_bg; */
205 Lisp_Object specified_bg
206 = Fplist_get (XCDR (img->spec), QCbackground);
207 Emacs_Color color;
208
209 /* If the user specified a color, try to use it; if not, use the
210 current frame background, ignoring any default background
211 color set by the image. */
212 if (STRINGP (specified_bg)
213 ? w32_defined_color (f, SSDATA (specified_bg), &color, false, false)
214 : (w32_query_frame_background_color (f, &color), true))
215 /* The user specified `:background', use that. */
216 {
217 DWORD red = (((DWORD) color.red) & 0xff00) << 8;
218 DWORD green = ((DWORD) color.green) & 0xff00;
219 DWORD blue = ((DWORD) color.blue) >> 8;
220 return red | green | blue;
221 }
222 return ((DWORD) 0xff000000);
223}
224
225int
226w32_load_image (struct frame *f, struct image *img,
227 Lisp_Object spec_file, Lisp_Object spec_data)
228{
229 Emacs_Pixmap pixmap;
230 GpStatus status = GenericError;
231 GpBitmap *pBitmap;
232 wchar_t filename[MAX_PATH];
233 ARGB bg_color;
234 Lisp_Object lisp_index, metadata;
235 unsigned int index, nframes;
236 double delay;
237
238 eassert (valid_image_p (img->spec));
239
240 /* This function only gets called if init_w32_gdiplus () was invoked. We have
241 a valid token and GDI+ is active. */
242 if (STRINGP (spec_file))
243 {
244 if (w32_unicode_filenames)
245 {
246 filename_to_utf16 (SSDATA (spec_file) , filename);
247 status = GdipCreateBitmapFromFile (filename, &pBitmap);
248 }
249 else
250 {
251 add_to_log ("GDI+ requires w32-unicode-filenames to be T");
252 status = GenericError;
253 }
254 }
255 else if (STRINGP (spec_data))
256 {
257 IStream *pStream = SHCreateMemStream ((BYTE *) SSDATA (spec_data),
258 SBYTES (spec_data));
259 if (pStream != NULL)
260 {
261 status = GdipCreateBitmapFromStream (pStream, &pBitmap);
262 IStream_Release (pStream);
263 }
264 }
265
266 metadata = Qnil;
267 if (status == Ok)
268 {
269 /* In multiframe pictures, select the first one */
270 lisp_index = Fplist_get (XCDR (img->spec), QCindex);
271 index = FIXNUMP (lisp_index) ? XFIXNAT (lisp_index) : 0;
272 status = w32_select_active_frame (pBitmap, index, &nframes, &delay);
273 if ((status == Ok))
274 {
275 if (nframes > 1)
276 metadata = Fcons (Qcount, Fcons (make_fixnum (nframes), metadata));
277 if (delay)
278 metadata = Fcons (Qdelay, Fcons (make_float (delay), metadata));
279 }
280 }
281
282 if (status == Ok)
283 {
284 bg_color = w32_image_bg_color (f, img);
285 status = GdipCreateHBITMAPFromBitmap (pBitmap, &pixmap, bg_color);
286 if (status == Ok)
287 {
288 UINT width, height;
289 GdipGetImageWidth (pBitmap, &width);
290 GdipGetImageHeight (pBitmap, &height);
291 img->width = width;
292 img->height = height;
293 img->pixmap = pixmap;
294 img->lisp_data = metadata;
295 }
296
297 GdipDisposeImage (pBitmap);
298 }
299
300 if (status != Ok)
301 {
302 add_to_log ("Unable to load image %s", img->spec);
303 return 0;
304 }
305 return 1;
306}
diff --git a/src/w32term.c b/src/w32term.c
index 5fa77d58e10..f19754df02c 100644
--- a/src/w32term.c
+++ b/src/w32term.c
@@ -1529,7 +1529,7 @@ w32_query_colors (struct frame *f, Emacs_Color *colors, int ncolors)
1529 1529
1530/* Store F's background color into *BGCOLOR. */ 1530/* Store F's background color into *BGCOLOR. */
1531 1531
1532static void 1532void
1533w32_query_frame_background_color (struct frame *f, Emacs_Color *bgcolor) 1533w32_query_frame_background_color (struct frame *f, Emacs_Color *bgcolor)
1534{ 1534{
1535 bgcolor->pixel = FRAME_BACKGROUND_PIXEL (f); 1535 bgcolor->pixel = FRAME_BACKGROUND_PIXEL (f);
diff --git a/src/w32term.h b/src/w32term.h
index 4e9234f239f..7ca00d0a099 100644
--- a/src/w32term.h
+++ b/src/w32term.h
@@ -75,7 +75,10 @@ struct w32_palette_entry {
75extern void w32_regenerate_palette (struct frame *f); 75extern void w32_regenerate_palette (struct frame *f);
76extern void w32_fullscreen_rect (HWND hwnd, int fsmode, RECT normal, 76extern void w32_fullscreen_rect (HWND hwnd, int fsmode, RECT normal,
77 RECT *rect); 77 RECT *rect);
78 78extern int w32_load_image (struct frame *f, struct image *img,
79 Lisp_Object spec_file, Lisp_Object spec_data);
80extern bool w32_gdiplus_startup (void);
81extern void w32_gdiplus_shutdown (void);
79 82
80/* For each display (currently only one on w32), we have a structure that 83/* For each display (currently only one on w32), we have a structure that
81 records information about it. */ 84 records information about it. */
@@ -248,6 +251,8 @@ extern int w32_display_pixel_height (struct w32_display_info *);
248extern int w32_display_pixel_width (struct w32_display_info *); 251extern int w32_display_pixel_width (struct w32_display_info *);
249extern void initialize_frame_menubar (struct frame *); 252extern void initialize_frame_menubar (struct frame *);
250extern void w32_dialog_in_progress (Lisp_Object in_progress); 253extern void w32_dialog_in_progress (Lisp_Object in_progress);
254extern void w32_query_frame_background_color (struct frame *f,
255 Emacs_Color *bgcolor);
251 256
252extern void w32_make_frame_visible (struct frame *f); 257extern void w32_make_frame_visible (struct frame *f);
253extern void w32_make_frame_invisible (struct frame *f); 258extern void w32_make_frame_invisible (struct frame *f);