diff options
| author | Juan José García-Ripoll | 2020-04-13 12:04:39 +0200 |
|---|---|---|
| committer | Eli Zaretskii | 2020-04-14 09:52:55 +0300 |
| commit | df254a7445a86dc25d133f2d79be8096190a8b96 (patch) | |
| tree | c6094f663793c61f4243483c0c6d310205005a83 | |
| parent | 7a9fb5d55c9bf612a38348d59e769ee915175e28 (diff) | |
| download | emacs-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.ac | 10 | ||||
| -rw-r--r-- | etc/NEWS | 7 | ||||
| -rw-r--r-- | lisp/term/w32-win.el | 2 | ||||
| -rw-r--r-- | src/image.c | 163 | ||||
| -rw-r--r-- | src/w32.c | 4 | ||||
| -rw-r--r-- | src/w32image.c | 306 | ||||
| -rw-r--r-- | src/w32term.c | 2 | ||||
| -rw-r--r-- | src/w32term.h | 7 |
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]) | |||
| 433 | OPTION_DEFAULT_ON([cairo],[don't compile with Cairo drawing]) | 433 | OPTION_DEFAULT_ON([cairo],[don't compile with Cairo drawing]) |
| 434 | OPTION_DEFAULT_ON([xml2],[don't compile with XML parsing support]) | 434 | OPTION_DEFAULT_ON([xml2],[don't compile with XML parsing support]) |
| 435 | OPTION_DEFAULT_OFF([imagemagick],[compile with ImageMagick image support]) | 435 | OPTION_DEFAULT_OFF([imagemagick],[compile with ImageMagick image support]) |
| 436 | OPTION_DEFAULT_OFF([native-image-api], [use native API's (GDI+ on Windows) for JPEG/TIFF/GIFF/PNG]) | ||
| 436 | OPTION_DEFAULT_ON([json], [don't compile with native JSON support]) | 437 | OPTION_DEFAULT_ON([json], [don't compile with native JSON support]) |
| 437 | 438 | ||
| 438 | OPTION_DEFAULT_ON([xft],[don't use XFT for anti aliased fonts]) | 439 | OPTION_DEFAULT_ON([xft],[don't use XFT for anti aliased fonts]) |
| @@ -2126,6 +2127,7 @@ LIB_WSOCK32= | |||
| 2126 | NTLIB= | 2127 | NTLIB= |
| 2127 | CM_OBJ="cm.o" | 2128 | CM_OBJ="cm.o" |
| 2128 | XARGS_LIMIT= | 2129 | XARGS_LIMIT= |
| 2130 | HAVE_NATIVE_IMAGE_API=no | ||
| 2129 | if test "${HAVE_W32}" = "yes"; then | 2131 | if 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} |
| @@ -386,6 +386,13 @@ and enable the MS-Windows native Input Method Editor (IME) at run | |||
| 386 | time. A companion function 'w32-get-ime-open-status' returns the | 386 | time. A companion function 'w32-get-ime-open-status' returns the |
| 387 | current IME activation status. | 387 | current IME activation status. |
| 388 | 388 | ||
| 389 | +++ | ||
| 390 | ** On MS-Windows, Emacs can now use the native image API to display images. | ||
| 391 | Emacs can now use the MS-Windows GDI+ library to load and display | ||
| 392 | images in JPEG, PNG, GIF and TIFF formats. This support is enabled | ||
| 393 | with --with-native-image-api, which automatically disables the use of | ||
| 394 | optional third party libraries for those formats. | ||
| 395 | |||
| 389 | 396 | ||
| 390 | ---------------------------------------------------------------------- | 397 | ---------------------------------------------------------------------- |
| 391 | This file is part of GNU Emacs. | 398 | This 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 | ||
| 3146 | static bool | 3146 | static bool |
| 3147 | xbm_image_p (Lisp_Object object) | 3147 | xbm_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 | ||
| 4157 | static bool | 4157 | static bool |
| 4158 | xpm_image_p (Lisp_Object object) | 4158 | xpm_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 | ||
| 5885 | static bool | 5885 | static bool |
| 5886 | pbm_image_p (Lisp_Object object) | 5886 | pbm_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 | |||
| 6245 | static bool | ||
| 6246 | init_native_image_functions (void) | ||
| 6247 | { | ||
| 6248 | return w32_gdiplus_startup (); | ||
| 6249 | } | ||
| 6250 | |||
| 6251 | /* Indices of image specification fields in native format, below. */ | ||
| 6252 | |||
| 6253 | enum 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 | |||
| 6272 | static 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 | |||
| 6289 | static bool | ||
| 6290 | native_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 | |||
| 6302 | static bool | ||
| 6303 | native_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 | ||
| 6277 | static bool | 6354 | static bool |
| 6278 | png_image_p (Lisp_Object object) | 6355 | png_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 | ||
| 6940 | static bool | 7016 | static bool |
| 6941 | jpeg_image_p (Lisp_Object object) | 7017 | jpeg_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 | ||
| 7516 | static bool | 7592 | static bool |
| 7517 | tiff_image_p (Lisp_Object object) | 7593 | tiff_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 | ||
| 7964 | static bool | 8040 | static bool |
| 7965 | gif_image_p (Lisp_Object object) | 8041 | gif_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 | ||
| 8576 | static bool | 8652 | static bool |
| 8577 | imagemagick_image_p (Lisp_Object object) | 8653 | imagemagick_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 | ||
| 9371 | static bool | 9447 | static bool |
| 9372 | svg_image_p (Lisp_Object object) | 9448 | svg_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 | ||
| 9839 | static bool | 9915 | static bool |
| 9840 | gs_image_p (Lisp_Object object) | 9916 | gs_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 | |||
| 10132 | initialize_image_type (struct image_type const *type) | 10208 | initialize_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 |
| @@ -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 | ||
| 10230 | void | 10234 | void |
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 | |||
| 3 | Copyright (C) 2020 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 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 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | 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 | /* 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 | ||
| 38 | DEF_DLL_FN (GpStatus, GdiplusStartup, (ULONG_PTR *, GdiplusStartupInput *, GdiplusStartupOutput *)); | ||
| 39 | DEF_DLL_FN (VOID, GdiplusShutdown, (ULONG_PTR)); | ||
| 40 | DEF_DLL_FN (GpStatus, GdipGetPropertyItemSize, (GpImage *, PROPID, UINT *)); | ||
| 41 | DEF_DLL_FN (GpStatus, GdipGetPropertyItem, (GpImage *, PROPID, UINT, PropertyItem *)); | ||
| 42 | DEF_DLL_FN (GpStatus, GdipImageGetFrameDimensionsCount, (GpImage *, UINT *)); | ||
| 43 | DEF_DLL_FN (GpStatus, GdipImageGetFrameDimensionsList, (GpImage *, GUID *, UINT)); | ||
| 44 | DEF_DLL_FN (GpStatus, GdipImageGetFrameCount, (GpImage *, GDIPCONST GUID *, UINT *)); | ||
| 45 | DEF_DLL_FN (GpStatus, GdipImageSelectActiveFrame, (GpImage*, GDIPCONST GUID *, UINT)); | ||
| 46 | DEF_DLL_FN (GpStatus, GdipCreateBitmapFromFile, (WCHAR *, GpBitmap **)); | ||
| 47 | DEF_DLL_FN (GpStatus, GdipCreateBitmapFromStream, (IStream *, GpBitmap **)); | ||
| 48 | DEF_DLL_FN (IStream *, SHCreateMemStream, (const BYTE *pInit, UINT cbInit)); | ||
| 49 | DEF_DLL_FN (GpStatus, GdipCreateHBITMAPFromBitmap, (GpBitmap *, HBITMAP *, ARGB)); | ||
| 50 | DEF_DLL_FN (GpStatus, GdipDisposeImage, (GpImage *)); | ||
| 51 | DEF_DLL_FN (GpStatus, GdipGetImageHeight, (GpImage *, UINT *)); | ||
| 52 | DEF_DLL_FN (GpStatus, GdipGetImageWidth, (GpImage *, UINT *)); | ||
| 53 | #endif | ||
| 54 | |||
| 55 | static int gdip_initialized = 0; | ||
| 56 | static ULONG_PTR token; | ||
| 57 | static GdiplusStartupInput input; | ||
| 58 | static GdiplusStartupOutput output; | ||
| 59 | |||
| 60 | bool | ||
| 61 | w32_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 | |||
| 134 | void | ||
| 135 | w32_gdiplus_shutdown (void) | ||
| 136 | { | ||
| 137 | GdiplusShutdown (token); | ||
| 138 | } | ||
| 139 | |||
| 140 | |||
| 141 | static double | ||
| 142 | w32_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 | |||
| 170 | static UINT | ||
| 171 | w32_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 | |||
| 201 | static ARGB | ||
| 202 | w32_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 | |||
| 225 | int | ||
| 226 | w32_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 | ||
| 1532 | static void | 1532 | void |
| 1533 | w32_query_frame_background_color (struct frame *f, Emacs_Color *bgcolor) | 1533 | w32_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 { | |||
| 75 | extern void w32_regenerate_palette (struct frame *f); | 75 | extern void w32_regenerate_palette (struct frame *f); |
| 76 | extern void w32_fullscreen_rect (HWND hwnd, int fsmode, RECT normal, | 76 | extern void w32_fullscreen_rect (HWND hwnd, int fsmode, RECT normal, |
| 77 | RECT *rect); | 77 | RECT *rect); |
| 78 | 78 | extern int w32_load_image (struct frame *f, struct image *img, | |
| 79 | Lisp_Object spec_file, Lisp_Object spec_data); | ||
| 80 | extern bool w32_gdiplus_startup (void); | ||
| 81 | extern 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 *); | |||
| 248 | extern int w32_display_pixel_width (struct w32_display_info *); | 251 | extern int w32_display_pixel_width (struct w32_display_info *); |
| 249 | extern void initialize_frame_menubar (struct frame *); | 252 | extern void initialize_frame_menubar (struct frame *); |
| 250 | extern void w32_dialog_in_progress (Lisp_Object in_progress); | 253 | extern void w32_dialog_in_progress (Lisp_Object in_progress); |
| 254 | extern void w32_query_frame_background_color (struct frame *f, | ||
| 255 | Emacs_Color *bgcolor); | ||
| 251 | 256 | ||
| 252 | extern void w32_make_frame_visible (struct frame *f); | 257 | extern void w32_make_frame_visible (struct frame *f); |
| 253 | extern void w32_make_frame_invisible (struct frame *f); | 258 | extern void w32_make_frame_invisible (struct frame *f); |