diff options
| author | Eli Zaretskii | 2020-04-14 18:10:41 +0300 |
|---|---|---|
| committer | Eli Zaretskii | 2020-04-14 18:10:41 +0300 |
| commit | e94206aaf608a899c81bb07fe91d26439f51b3f8 (patch) | |
| tree | a4a24407f1ba3d70ae192a1aad954a2bed3e91e1 /src | |
| parent | df254a7445a86dc25d133f2d79be8096190a8b96 (diff) | |
| download | emacs-e94206aaf608a899c81bb07fe91d26439f51b3f8.tar.gz emacs-e94206aaf608a899c81bb07fe91d26439f51b3f8.zip | |
Make use of MS-Windows native image API be selectable at run time
* configure.ac: Minor cleanup in how w32image.o is added to the
build when native image APIs are requested.
* src/w32gui.h (w32_load_image, w32_can_use_native_image_api)
(w32_gdiplus_shutdown): Move prototypes from w32term.h here, since
w32.c doesn't include w32term.h.
* src/image.c (struct image_type): No need to pass TYPE to the
'valid_p' method. All callers changed.
(initialize_image_type) [HAVE_NATIVE_IMAGE_API]: Call
'image_can_use_native_api' before trying image-specific methods.
(image_can_use_native_api): New function.
(image_types): Remove the native_image_type parts.
(syms_of_image): New symbol 'native-image'.
(parse_image_spec): Accept native-image "type" for any image type.
* src/w32term.c (syms_of_w32term): New variable
'w32-use-native-image-API'.
* src/w32image.c: (w32_can_use_native_image_api): New function.
(gdiplus_init): Rename from w32_gdiplus_startup. Simplify code.
Move the call to GdiplusStartup to a separate function. Use
ordinal number for SHCreateMemStream if cannot load it by name.
(w32_load_image): Ignore Win32Error status from
w32_select_active_frame.
Move DEFSYMs from here...
* src/image.c (syms_of_image) [HAVE_NATIVE_IMAGE_API]: ...to here.
* etc/NEWS: Update the entry about native image API use.
Diffstat (limited to 'src')
| -rw-r--r-- | src/image.c | 134 | ||||
| -rw-r--r-- | src/w32.c | 2 | ||||
| -rw-r--r-- | src/w32gui.h | 6 | ||||
| -rw-r--r-- | src/w32image.c | 224 | ||||
| -rw-r--r-- | src/w32term.c | 19 | ||||
| -rw-r--r-- | src/w32term.h | 4 |
6 files changed, 244 insertions, 145 deletions
diff --git a/src/image.c b/src/image.c index ff2d12fa1a1..4ef3e9d3e4c 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, Lisp_Object type); | 754 | bool (*valid_p) (Lisp_Object spec); |
| 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, builtin_lisp_symbol (type->type)); | 810 | return type->valid_p (object); |
| 811 | } | 811 | } |
| 812 | break; | 812 | break; |
| 813 | } | 813 | } |
| @@ -816,7 +816,6 @@ valid_image_p (Lisp_Object object) | |||
| 816 | return false; | 816 | return false; |
| 817 | } | 817 | } |
| 818 | 818 | ||
| 819 | |||
| 820 | /* Log error message with format string FORMAT and trailing arguments. | 819 | /* Log error message with format string FORMAT and trailing arguments. |
| 821 | Signaling an error, e.g. when an image cannot be loaded, is not a | 820 | Signaling an error, e.g. when an image cannot be loaded, is not a |
| 822 | good idea because this would interrupt redisplay, and the error | 821 | good idea because this would interrupt redisplay, and the error |
| @@ -1004,7 +1003,8 @@ parse_image_spec (Lisp_Object spec, struct image_keyword *keywords, | |||
| 1004 | break; | 1003 | break; |
| 1005 | } | 1004 | } |
| 1006 | 1005 | ||
| 1007 | if (EQ (key, QCtype) && !EQ (type, value)) | 1006 | if (EQ (key, QCtype) |
| 1007 | && !(EQ (type, value) || EQ (type, Qnative_image))) | ||
| 1008 | return false; | 1008 | return false; |
| 1009 | } | 1009 | } |
| 1010 | 1010 | ||
| @@ -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, Lisp_Object type) | 3147 | xbm_image_p (Lisp_Object object) |
| 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, type)) | 3152 | if (!parse_image_spec (object, kw, XBM_LAST, Qxbm)) |
| 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, Qxbm)); | 3700 | eassert (xbm_image_p (img->spec)); |
| 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, Lisp_Object type) | 4158 | xpm_image_p (Lisp_Object object) |
| 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, type) | 4162 | return (parse_image_spec (object, fmt, XPM_LAST, Qxpm) |
| 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, Lisp_Object type) | 5886 | pbm_image_p (Lisp_Object object) |
| 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, type)) | 5892 | if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)) |
| 5893 | return 0; | 5893 | return 0; |
| 5894 | 5894 | ||
| 5895 | /* Must specify either :data or :file. */ | 5895 | /* Must specify either :data or :file. */ |
| @@ -6235,21 +6235,30 @@ pbm_load (struct frame *f, struct image *img) | |||
| 6235 | /*********************************************************************** | 6235 | /*********************************************************************** |
| 6236 | NATIVE IMAGE HANDLING | 6236 | NATIVE IMAGE HANDLING |
| 6237 | ***********************************************************************/ | 6237 | ***********************************************************************/ |
| 6238 | #if defined(HAVE_NATIVE_IMAGE_API) && defined(HAVE_NTGUI) | 6238 | |
| 6239 | static bool | ||
| 6240 | image_can_use_native_api (Lisp_Object type) | ||
| 6241 | { | ||
| 6242 | #if HAVE_NATIVE_IMAGE_API | ||
| 6243 | # ifdef HAVE_NTGUI | ||
| 6244 | return w32_can_use_native_image_api (type); | ||
| 6245 | # else | ||
| 6246 | return false; | ||
| 6247 | # endif | ||
| 6248 | #else | ||
| 6249 | return false; | ||
| 6250 | #endif | ||
| 6251 | } | ||
| 6252 | |||
| 6253 | #if HAVE_NATIVE_IMAGE_API | ||
| 6254 | |||
| 6239 | /* | 6255 | /* |
| 6240 | * These functions are actually defined in the OS-native implementation | 6256 | * These functions are actually defined in the OS-native implementation |
| 6241 | * file. Currently, for Windows GDI+ interface, w32image.c, but other | 6257 | * file. Currently, for Windows GDI+ interface, w32image.c, but other |
| 6242 | * operating systems can follow suit. | 6258 | * operating systems can follow suit. |
| 6243 | */ | 6259 | */ |
| 6244 | 6260 | ||
| 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. */ | 6261 | /* Indices of image specification fields in native format, below. */ |
| 6252 | |||
| 6253 | enum native_image_keyword_index | 6262 | enum native_image_keyword_index |
| 6254 | { | 6263 | { |
| 6255 | NATIVE_IMAGE_TYPE, | 6264 | NATIVE_IMAGE_TYPE, |
| @@ -6268,7 +6277,6 @@ enum native_image_keyword_index | |||
| 6268 | 6277 | ||
| 6269 | /* Vector of image_keyword structures describing the format | 6278 | /* Vector of image_keyword structures describing the format |
| 6270 | of valid user-defined image specifications. */ | 6279 | of valid user-defined image specifications. */ |
| 6271 | |||
| 6272 | static const struct image_keyword native_image_format[] = | 6280 | static const struct image_keyword native_image_format[] = |
| 6273 | { | 6281 | { |
| 6274 | {":type", IMAGE_SYMBOL_VALUE, 1}, | 6282 | {":type", IMAGE_SYMBOL_VALUE, 1}, |
| @@ -6287,12 +6295,12 @@ static const struct image_keyword native_image_format[] = | |||
| 6287 | /* Return true if OBJECT is a valid native API image specification. */ | 6295 | /* Return true if OBJECT is a valid native API image specification. */ |
| 6288 | 6296 | ||
| 6289 | static bool | 6297 | static bool |
| 6290 | native_image_p (Lisp_Object object, Lisp_Object type) | 6298 | native_image_p (Lisp_Object object) |
| 6291 | { | 6299 | { |
| 6292 | struct image_keyword fmt[NATIVE_IMAGE_LAST]; | 6300 | struct image_keyword fmt[NATIVE_IMAGE_LAST]; |
| 6293 | memcpy (fmt, native_image_format, sizeof fmt); | 6301 | memcpy (fmt, native_image_format, sizeof fmt); |
| 6294 | 6302 | ||
| 6295 | if (!parse_image_spec (object, fmt, 10, type)) | 6303 | if (!parse_image_spec (object, fmt, 10, Qnative_image)) |
| 6296 | return 0; | 6304 | return 0; |
| 6297 | 6305 | ||
| 6298 | /* Must specify either the :data or :file keyword. */ | 6306 | /* Must specify either the :data or :file keyword. */ |
| @@ -6302,11 +6310,17 @@ native_image_p (Lisp_Object object, Lisp_Object type) | |||
| 6302 | static bool | 6310 | static bool |
| 6303 | native_image_load (struct frame *f, struct image *img) | 6311 | native_image_load (struct frame *f, struct image *img) |
| 6304 | { | 6312 | { |
| 6313 | |||
| 6314 | # ifdef HAVE_NTGUI | ||
| 6305 | return w32_load_image (f, img, | 6315 | return w32_load_image (f, img, |
| 6306 | image_spec_value (img->spec, QCfile, NULL), | 6316 | image_spec_value (img->spec, QCfile, NULL), |
| 6307 | image_spec_value (img->spec, QCdata, NULL)); | 6317 | image_spec_value (img->spec, QCdata, NULL)); |
| 6318 | # else | ||
| 6319 | return 0; | ||
| 6320 | # endif | ||
| 6308 | } | 6321 | } |
| 6309 | #endif | 6322 | |
| 6323 | #endif /* HAVE_NATIVE_IMAGE_API */ | ||
| 6310 | 6324 | ||
| 6311 | 6325 | ||
| 6312 | /*********************************************************************** | 6326 | /*********************************************************************** |
| @@ -6352,12 +6366,12 @@ static const struct image_keyword png_format[PNG_LAST] = | |||
| 6352 | /* Return true if OBJECT is a valid PNG image specification. */ | 6366 | /* Return true if OBJECT is a valid PNG image specification. */ |
| 6353 | 6367 | ||
| 6354 | static bool | 6368 | static bool |
| 6355 | png_image_p (Lisp_Object object, Lisp_Object type) | 6369 | png_image_p (Lisp_Object object) |
| 6356 | { | 6370 | { |
| 6357 | struct image_keyword fmt[PNG_LAST]; | 6371 | struct image_keyword fmt[PNG_LAST]; |
| 6358 | memcpy (fmt, png_format, sizeof fmt); | 6372 | memcpy (fmt, png_format, sizeof fmt); |
| 6359 | 6373 | ||
| 6360 | if (!parse_image_spec (object, fmt, PNG_LAST, type)) | 6374 | if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)) |
| 6361 | return 0; | 6375 | return 0; |
| 6362 | 6376 | ||
| 6363 | /* Must specify either the :data or :file keyword. */ | 6377 | /* Must specify either the :data or :file keyword. */ |
| @@ -7014,13 +7028,13 @@ static const struct image_keyword jpeg_format[JPEG_LAST] = | |||
| 7014 | /* Return true if OBJECT is a valid JPEG image specification. */ | 7028 | /* Return true if OBJECT is a valid JPEG image specification. */ |
| 7015 | 7029 | ||
| 7016 | static bool | 7030 | static bool |
| 7017 | jpeg_image_p (Lisp_Object object, Lisp_Object type) | 7031 | jpeg_image_p (Lisp_Object object) |
| 7018 | { | 7032 | { |
| 7019 | struct image_keyword fmt[JPEG_LAST]; | 7033 | struct image_keyword fmt[JPEG_LAST]; |
| 7020 | 7034 | ||
| 7021 | memcpy (fmt, jpeg_format, sizeof fmt); | 7035 | memcpy (fmt, jpeg_format, sizeof fmt); |
| 7022 | 7036 | ||
| 7023 | if (!parse_image_spec (object, fmt, JPEG_LAST, type)) | 7037 | if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)) |
| 7024 | return 0; | 7038 | return 0; |
| 7025 | 7039 | ||
| 7026 | /* Must specify either the :data or :file keyword. */ | 7040 | /* Must specify either the :data or :file keyword. */ |
| @@ -7590,12 +7604,12 @@ static const struct image_keyword tiff_format[TIFF_LAST] = | |||
| 7590 | /* Return true if OBJECT is a valid TIFF image specification. */ | 7604 | /* Return true if OBJECT is a valid TIFF image specification. */ |
| 7591 | 7605 | ||
| 7592 | static bool | 7606 | static bool |
| 7593 | tiff_image_p (Lisp_Object object, Lisp_Object type) | 7607 | tiff_image_p (Lisp_Object object) |
| 7594 | { | 7608 | { |
| 7595 | struct image_keyword fmt[TIFF_LAST]; | 7609 | struct image_keyword fmt[TIFF_LAST]; |
| 7596 | memcpy (fmt, tiff_format, sizeof fmt); | 7610 | memcpy (fmt, tiff_format, sizeof fmt); |
| 7597 | 7611 | ||
| 7598 | if (!parse_image_spec (object, fmt, TIFF_LAST, type)) | 7612 | if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)) |
| 7599 | return 0; | 7613 | return 0; |
| 7600 | 7614 | ||
| 7601 | /* Must specify either the :data or :file keyword. */ | 7615 | /* Must specify either the :data or :file keyword. */ |
| @@ -8038,12 +8052,12 @@ gif_clear_image (struct frame *f, struct image *img) | |||
| 8038 | /* Return true if OBJECT is a valid GIF image specification. */ | 8052 | /* Return true if OBJECT is a valid GIF image specification. */ |
| 8039 | 8053 | ||
| 8040 | static bool | 8054 | static bool |
| 8041 | gif_image_p (Lisp_Object object, Lisp_Object type) | 8055 | gif_image_p (Lisp_Object object) |
| 8042 | { | 8056 | { |
| 8043 | struct image_keyword fmt[GIF_LAST]; | 8057 | struct image_keyword fmt[GIF_LAST]; |
| 8044 | memcpy (fmt, gif_format, sizeof fmt); | 8058 | memcpy (fmt, gif_format, sizeof fmt); |
| 8045 | 8059 | ||
| 8046 | if (!parse_image_spec (object, fmt, GIF_LAST, type)) | 8060 | if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)) |
| 8047 | return 0; | 8061 | return 0; |
| 8048 | 8062 | ||
| 8049 | /* Must specify either the :data or :file keyword. */ | 8063 | /* Must specify either the :data or :file keyword. */ |
| @@ -8650,12 +8664,12 @@ imagemagick_clear_image (struct frame *f, | |||
| 8650 | identify the IMAGEMAGICK format. */ | 8664 | identify the IMAGEMAGICK format. */ |
| 8651 | 8665 | ||
| 8652 | static bool | 8666 | static bool |
| 8653 | imagemagick_image_p (Lisp_Object object, Lisp_Object type) | 8667 | imagemagick_image_p (Lisp_Object object) |
| 8654 | { | 8668 | { |
| 8655 | struct image_keyword fmt[IMAGEMAGICK_LAST]; | 8669 | struct image_keyword fmt[IMAGEMAGICK_LAST]; |
| 8656 | memcpy (fmt, imagemagick_format, sizeof fmt); | 8670 | memcpy (fmt, imagemagick_format, sizeof fmt); |
| 8657 | 8671 | ||
| 8658 | if (!parse_image_spec (object, fmt, IMAGEMAGICK_LAST, type)) | 8672 | if (!parse_image_spec (object, fmt, IMAGEMAGICK_LAST, Qimagemagick)) |
| 8659 | return 0; | 8673 | return 0; |
| 8660 | 8674 | ||
| 8661 | /* Must specify either the :data or :file keyword. */ | 8675 | /* Must specify either the :data or :file keyword. */ |
| @@ -9445,12 +9459,12 @@ static const struct image_keyword svg_format[SVG_LAST] = | |||
| 9445 | identify the SVG format. */ | 9459 | identify the SVG format. */ |
| 9446 | 9460 | ||
| 9447 | static bool | 9461 | static bool |
| 9448 | svg_image_p (Lisp_Object object, Lisp_Object type) | 9462 | svg_image_p (Lisp_Object object) |
| 9449 | { | 9463 | { |
| 9450 | struct image_keyword fmt[SVG_LAST]; | 9464 | struct image_keyword fmt[SVG_LAST]; |
| 9451 | memcpy (fmt, svg_format, sizeof fmt); | 9465 | memcpy (fmt, svg_format, sizeof fmt); |
| 9452 | 9466 | ||
| 9453 | if (!parse_image_spec (object, fmt, SVG_LAST, type)) | 9467 | if (!parse_image_spec (object, fmt, SVG_LAST, Qsvg)) |
| 9454 | return 0; | 9468 | return 0; |
| 9455 | 9469 | ||
| 9456 | /* Must specify either the :data or :file keyword. */ | 9470 | /* Must specify either the :data or :file keyword. */ |
| @@ -9913,7 +9927,7 @@ static const struct image_keyword gs_format[GS_LAST] = | |||
| 9913 | specification. */ | 9927 | specification. */ |
| 9914 | 9928 | ||
| 9915 | static bool | 9929 | static bool |
| 9916 | gs_image_p (Lisp_Object object, Lisp_Object type) | 9930 | gs_image_p (Lisp_Object object) |
| 9917 | { | 9931 | { |
| 9918 | struct image_keyword fmt[GS_LAST]; | 9932 | struct image_keyword fmt[GS_LAST]; |
| 9919 | Lisp_Object tem; | 9933 | Lisp_Object tem; |
| @@ -9921,7 +9935,7 @@ gs_image_p (Lisp_Object object, Lisp_Object type) | |||
| 9921 | 9935 | ||
| 9922 | memcpy (fmt, gs_format, sizeof fmt); | 9936 | memcpy (fmt, gs_format, sizeof fmt); |
| 9923 | 9937 | ||
| 9924 | if (!parse_image_spec (object, fmt, GS_LAST, type)) | 9938 | if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)) |
| 9925 | return 0; | 9939 | return 0; |
| 9926 | 9940 | ||
| 9927 | /* Bounding box must be a list or vector containing 4 integers. */ | 9941 | /* Bounding box must be a list or vector containing 4 integers. */ |
| @@ -10208,20 +10222,19 @@ static bool | |||
| 10208 | initialize_image_type (struct image_type const *type) | 10222 | initialize_image_type (struct image_type const *type) |
| 10209 | { | 10223 | { |
| 10210 | #ifdef WINDOWSNT | 10224 | #ifdef WINDOWSNT |
| 10211 | Lisp_Object typesym, tested; | 10225 | Lisp_Object typesym = builtin_lisp_symbol (type->type); |
| 10212 | bool (*init) (void) = type->init; | ||
| 10213 | 10226 | ||
| 10214 | #ifdef HAVE_NATIVE_IMAGE_API | 10227 | #ifdef HAVE_NATIVE_IMAGE_API |
| 10215 | if (init == init_native_image_functions) | 10228 | if (image_can_use_native_api (typesym)) |
| 10216 | return init(); | 10229 | return true; |
| 10217 | #endif | 10230 | #endif |
| 10218 | 10231 | ||
| 10219 | typesym = builtin_lisp_symbol (type->type); | 10232 | Lisp_Object tested = Fassq (typesym, Vlibrary_cache); |
| 10220 | tested = Fassq (typesym, Vlibrary_cache); | ||
| 10221 | /* If we failed to load the library before, don't try again. */ | 10233 | /* If we failed to load the library before, don't try again. */ |
| 10222 | if (CONSP (tested)) | 10234 | if (CONSP (tested)) |
| 10223 | return !NILP (XCDR (tested)) ? true : false; | 10235 | return !NILP (XCDR (tested)) ? true : false; |
| 10224 | 10236 | ||
| 10237 | bool (*init) (void) = type->init; | ||
| 10225 | if (init) | 10238 | if (init) |
| 10226 | { | 10239 | { |
| 10227 | bool type_valid = init (); | 10240 | bool type_valid = init (); |
| @@ -10248,16 +10261,6 @@ static struct image_type const image_types[] = | |||
| 10248 | { SYMBOL_INDEX (Qsvg), svg_image_p, svg_load, image_clear_image, | 10261 | { SYMBOL_INDEX (Qsvg), svg_image_p, svg_load, image_clear_image, |
| 10249 | IMAGE_TYPE_INIT (init_svg_functions) }, | 10262 | IMAGE_TYPE_INIT (init_svg_functions) }, |
| 10250 | #endif | 10263 | #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 | ||
| 10261 | #if defined HAVE_PNG || defined HAVE_NS | 10264 | #if defined HAVE_PNG || defined HAVE_NS |
| 10262 | { SYMBOL_INDEX (Qpng), png_image_p, png_load, image_clear_image, | 10265 | { SYMBOL_INDEX (Qpng), png_image_p, png_load, image_clear_image, |
| 10263 | IMAGE_TYPE_INIT (init_png_functions) }, | 10266 | IMAGE_TYPE_INIT (init_png_functions) }, |
| @@ -10282,23 +10285,28 @@ static struct image_type const image_types[] = | |||
| 10282 | { SYMBOL_INDEX (Qpbm), pbm_image_p, pbm_load, image_clear_image }, | 10285 | { SYMBOL_INDEX (Qpbm), pbm_image_p, pbm_load, image_clear_image }, |
| 10283 | }; | 10286 | }; |
| 10284 | 10287 | ||
| 10288 | #ifdef HAVE_NATIVE_IMAGE_API | ||
| 10289 | struct image_type native_image_type = | ||
| 10290 | { SYMBOL_INDEX (Qnative_image), native_image_p, native_image_load, | ||
| 10291 | image_clear_image }; | ||
| 10292 | #endif | ||
| 10293 | |||
| 10285 | /* Look up image type TYPE, and return a pointer to its image_type | 10294 | /* Look up image type TYPE, and return a pointer to its image_type |
| 10286 | structure. Return 0 if TYPE is not a known image type. */ | 10295 | structure. Return 0 if TYPE is not a known image type. */ |
| 10287 | 10296 | ||
| 10288 | static struct image_type const * | 10297 | static struct image_type const * |
| 10289 | lookup_image_type (Lisp_Object type) | 10298 | lookup_image_type (Lisp_Object type) |
| 10290 | { | 10299 | { |
| 10300 | #ifdef HAVE_NATIVE_IMAGE_API | ||
| 10301 | if (image_can_use_native_api (type)) | ||
| 10302 | return &native_image_type; | ||
| 10303 | #endif | ||
| 10304 | |||
| 10291 | for (int i = 0; i < ARRAYELTS (image_types); i++) | 10305 | for (int i = 0; i < ARRAYELTS (image_types); i++) |
| 10292 | { | 10306 | { |
| 10293 | struct image_type const *r = &image_types[i]; | 10307 | struct image_type const *r = &image_types[i]; |
| 10294 | if (EQ (type, builtin_lisp_symbol (r->type))) | 10308 | 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 | ||
| 10300 | return initialize_image_type (r) ? r : NULL; | 10309 | return initialize_image_type (r) ? r : NULL; |
| 10301 | #endif | ||
| 10302 | } | 10310 | } |
| 10303 | return NULL; | 10311 | return NULL; |
| 10304 | } | 10312 | } |
| @@ -10454,6 +10462,14 @@ non-numeric, there is no explicit limit on the size of images. */); | |||
| 10454 | #endif /* HAVE_NTGUI */ | 10462 | #endif /* HAVE_NTGUI */ |
| 10455 | #endif /* HAVE_RSVG */ | 10463 | #endif /* HAVE_RSVG */ |
| 10456 | 10464 | ||
| 10465 | #if HAVE_NATIVE_IMAGE_API | ||
| 10466 | DEFSYM (Qnative_image, "native-image"); | ||
| 10467 | # ifdef HAVE_NTGUI | ||
| 10468 | DEFSYM (Qgdiplus, "gdiplus"); | ||
| 10469 | DEFSYM (Qshlwapi, "shlwapi"); | ||
| 10470 | # endif | ||
| 10471 | #endif | ||
| 10472 | |||
| 10457 | defsubr (&Sinit_image_library); | 10473 | defsubr (&Sinit_image_library); |
| 10458 | #ifdef HAVE_IMAGEMAGICK | 10474 | #ifdef HAVE_IMAGEMAGICK |
| 10459 | defsubr (&Simagemagick_types); | 10475 | defsubr (&Simagemagick_types); |
| @@ -10226,7 +10226,7 @@ term_ntproc (int ignored) | |||
| 10226 | 10226 | ||
| 10227 | term_w32select (); | 10227 | term_w32select (); |
| 10228 | 10228 | ||
| 10229 | #ifdef HAVE_GDIPLUS | 10229 | #if HAVE_NATIVE_IMAGE_API |
| 10230 | w32_gdiplus_shutdown (); | 10230 | w32_gdiplus_shutdown (); |
| 10231 | #endif | 10231 | #endif |
| 10232 | } | 10232 | } |
diff --git a/src/w32gui.h b/src/w32gui.h index 5cc64287291..dfec1f08617 100644 --- a/src/w32gui.h +++ b/src/w32gui.h | |||
| @@ -41,6 +41,12 @@ typedef struct _XImage | |||
| 41 | /* Optional RGBQUAD array for palette follows (see BITMAPINFO docs). */ | 41 | /* Optional RGBQUAD array for palette follows (see BITMAPINFO docs). */ |
| 42 | } XImage; | 42 | } XImage; |
| 43 | 43 | ||
| 44 | struct image; | ||
| 45 | extern int w32_load_image (struct frame *f, struct image *img, | ||
| 46 | Lisp_Object spec_file, Lisp_Object spec_data); | ||
| 47 | extern bool w32_can_use_native_image_api (Lisp_Object); | ||
| 48 | extern void w32_gdiplus_shutdown (void); | ||
| 49 | |||
| 44 | #define FACE_DEFAULT (~0) | 50 | #define FACE_DEFAULT (~0) |
| 45 | 51 | ||
| 46 | extern HINSTANCE hinst; | 52 | extern HINSTANCE hinst; |
diff --git a/src/w32image.c b/src/w32image.c index fe32660f712..6a3e37ce0ee 100644 --- a/src/w32image.c +++ b/src/w32image.c | |||
| @@ -23,7 +23,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 23 | #include "lisp.h" | 23 | #include "lisp.h" |
| 24 | #include "dispextern.h" | 24 | #include "dispextern.h" |
| 25 | #define COBJMACROS | 25 | #define COBJMACROS |
| 26 | #ifdef MINGW_W64 | ||
| 27 | /* FIXME: Do we need to include objidl.h? */ | ||
| 26 | #include <objidl.h> | 28 | #include <objidl.h> |
| 29 | #endif | ||
| 27 | #include <wtypes.h> | 30 | #include <wtypes.h> |
| 28 | #include <gdiplus.h> | 31 | #include <gdiplus.h> |
| 29 | #include <shlwapi.h> | 32 | #include <shlwapi.h> |
| @@ -32,53 +35,39 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 32 | #include "frame.h" | 35 | #include "frame.h" |
| 33 | #include "coding.h" | 36 | #include "coding.h" |
| 34 | 37 | ||
| 35 | /*#define LINK_GDIPLUS_STATICALLY 1*/ | 38 | #ifdef WINDOWSNT |
| 36 | 39 | ||
| 37 | #ifndef LINK_GDIPLUS_STATICALLY | 40 | DEF_DLL_FN (GpStatus, GdiplusStartup, |
| 38 | DEF_DLL_FN (GpStatus, GdiplusStartup, (ULONG_PTR *, GdiplusStartupInput *, GdiplusStartupOutput *)); | 41 | (ULONG_PTR *, GdiplusStartupInput *, GdiplusStartupOutput *)); |
| 39 | DEF_DLL_FN (VOID, GdiplusShutdown, (ULONG_PTR)); | 42 | DEF_DLL_FN (VOID, GdiplusShutdown, (ULONG_PTR)); |
| 40 | DEF_DLL_FN (GpStatus, GdipGetPropertyItemSize, (GpImage *, PROPID, UINT *)); | 43 | DEF_DLL_FN (GpStatus, GdipGetPropertyItemSize, |
| 41 | DEF_DLL_FN (GpStatus, GdipGetPropertyItem, (GpImage *, PROPID, UINT, PropertyItem *)); | 44 | (GpImage *, PROPID, UINT *)); |
| 45 | DEF_DLL_FN (GpStatus, GdipGetPropertyItem, | ||
| 46 | (GpImage *, PROPID, UINT, PropertyItem *)); | ||
| 42 | DEF_DLL_FN (GpStatus, GdipImageGetFrameDimensionsCount, (GpImage *, UINT *)); | 47 | DEF_DLL_FN (GpStatus, GdipImageGetFrameDimensionsCount, (GpImage *, UINT *)); |
| 43 | DEF_DLL_FN (GpStatus, GdipImageGetFrameDimensionsList, (GpImage *, GUID *, UINT)); | 48 | DEF_DLL_FN (GpStatus, GdipImageGetFrameDimensionsList, |
| 44 | DEF_DLL_FN (GpStatus, GdipImageGetFrameCount, (GpImage *, GDIPCONST GUID *, UINT *)); | 49 | (GpImage *, GUID *, UINT)); |
| 45 | DEF_DLL_FN (GpStatus, GdipImageSelectActiveFrame, (GpImage*, GDIPCONST GUID *, UINT)); | 50 | DEF_DLL_FN (GpStatus, GdipImageGetFrameCount, |
| 51 | (GpImage *, GDIPCONST GUID *, UINT *)); | ||
| 52 | DEF_DLL_FN (GpStatus, GdipImageSelectActiveFrame, | ||
| 53 | (GpImage*, GDIPCONST GUID *, UINT)); | ||
| 46 | DEF_DLL_FN (GpStatus, GdipCreateBitmapFromFile, (WCHAR *, GpBitmap **)); | 54 | DEF_DLL_FN (GpStatus, GdipCreateBitmapFromFile, (WCHAR *, GpBitmap **)); |
| 47 | DEF_DLL_FN (GpStatus, GdipCreateBitmapFromStream, (IStream *, GpBitmap **)); | 55 | DEF_DLL_FN (GpStatus, GdipCreateBitmapFromStream, (IStream *, GpBitmap **)); |
| 48 | DEF_DLL_FN (IStream *, SHCreateMemStream, (const BYTE *pInit, UINT cbInit)); | 56 | DEF_DLL_FN (IStream *, SHCreateMemStream, (const BYTE *pInit, UINT cbInit)); |
| 49 | DEF_DLL_FN (GpStatus, GdipCreateHBITMAPFromBitmap, (GpBitmap *, HBITMAP *, ARGB)); | 57 | DEF_DLL_FN (GpStatus, GdipCreateHBITMAPFromBitmap, |
| 58 | (GpBitmap *, HBITMAP *, ARGB)); | ||
| 50 | DEF_DLL_FN (GpStatus, GdipDisposeImage, (GpImage *)); | 59 | DEF_DLL_FN (GpStatus, GdipDisposeImage, (GpImage *)); |
| 51 | DEF_DLL_FN (GpStatus, GdipGetImageHeight, (GpImage *, UINT *)); | 60 | DEF_DLL_FN (GpStatus, GdipGetImageHeight, (GpImage *, UINT *)); |
| 52 | DEF_DLL_FN (GpStatus, GdipGetImageWidth, (GpImage *, UINT *)); | 61 | 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 | 62 | ||
| 60 | bool | 63 | static bool |
| 61 | w32_gdiplus_startup (void) | 64 | gdiplus_init (void) |
| 62 | { | 65 | { |
| 63 | HANDLE gdiplus_lib, shlwapi_lib; | 66 | HANDLE gdiplus_lib, shlwapi_lib; |
| 64 | GpStatus status; | ||
| 65 | 67 | ||
| 66 | if (gdip_initialized < 0) | 68 | if (!((gdiplus_lib = w32_delayed_load (Qgdiplus)) |
| 67 | return 0; | 69 | && (shlwapi_lib = w32_delayed_load (Qshlwapi)))) |
| 68 | else if (gdip_initialized) | 70 | return false; |
| 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 | 71 | ||
| 83 | LOAD_DLL_FN (gdiplus_lib, GdiplusStartup); | 72 | LOAD_DLL_FN (gdiplus_lib, GdiplusStartup); |
| 84 | LOAD_DLL_FN (gdiplus_lib, GdiplusShutdown); | 73 | LOAD_DLL_FN (gdiplus_lib, GdiplusShutdown); |
| @@ -94,7 +83,41 @@ w32_gdiplus_startup (void) | |||
| 94 | LOAD_DLL_FN (gdiplus_lib, GdipDisposeImage); | 83 | LOAD_DLL_FN (gdiplus_lib, GdipDisposeImage); |
| 95 | LOAD_DLL_FN (gdiplus_lib, GdipGetImageHeight); | 84 | LOAD_DLL_FN (gdiplus_lib, GdipGetImageHeight); |
| 96 | LOAD_DLL_FN (gdiplus_lib, GdipGetImageWidth); | 85 | LOAD_DLL_FN (gdiplus_lib, GdipGetImageWidth); |
| 97 | LOAD_DLL_FN (shlwapi_lib, SHCreateMemStream); | 86 | /* LOAD_DLL_FN (shlwapi_lib, SHCreateMemStream); */ |
| 87 | |||
| 88 | /* The following terrible kludge is required to use native image API | ||
| 89 | on Windows before Vista, because SHCreateMemStream was not | ||
| 90 | exported by name in those versions, only by ordinal number. */ | ||
| 91 | fn_SHCreateMemStream = | ||
| 92 | (W32_PFN_SHCreateMemStream) get_proc_addr (shlwapi_lib, | ||
| 93 | "SHCreateMemStream"); | ||
| 94 | if (!fn_SHCreateMemStream) | ||
| 95 | { | ||
| 96 | fn_SHCreateMemStream = | ||
| 97 | (W32_PFN_SHCreateMemStream) get_proc_addr (shlwapi_lib, | ||
| 98 | MAKEINTRESOURCEA (12)); | ||
| 99 | if (!fn_SHCreateMemStream) | ||
| 100 | return false; | ||
| 101 | } | ||
| 102 | |||
| 103 | return true; | ||
| 104 | } | ||
| 105 | |||
| 106 | # undef GdiplusStartup | ||
| 107 | # undef GdiplusShutdown | ||
| 108 | # undef GdipGetPropertyItemSize | ||
| 109 | # undef GdipGetPropertyItem | ||
| 110 | # undef GdipImageGetFrameDimensionsCount | ||
| 111 | # undef GdipImageGetFrameDimensionsList | ||
| 112 | # undef GdipImageGetFrameCount | ||
| 113 | # undef GdipImageSelectActiveFrame | ||
| 114 | # undef GdipCreateBitmapFromFile | ||
| 115 | # undef GdipCreateBitmapFromStream | ||
| 116 | # undef SHCreateMemStream | ||
| 117 | # undef GdipCreateHBITMAPFromBitmap | ||
| 118 | # undef GdipDisposeImage | ||
| 119 | # undef GdipGetImageHeight | ||
| 120 | # undef GdipGetImageWidth | ||
| 98 | 121 | ||
| 99 | # define GdiplusStartup fn_GdiplusStartup | 122 | # define GdiplusStartup fn_GdiplusStartup |
| 100 | # define GdiplusShutdown fn_GdiplusShutdown | 123 | # define GdiplusShutdown fn_GdiplusShutdown |
| @@ -111,32 +134,71 @@ w32_gdiplus_startup (void) | |||
| 111 | # define GdipDisposeImage fn_GdipDisposeImage | 134 | # define GdipDisposeImage fn_GdipDisposeImage |
| 112 | # define GdipGetImageHeight fn_GdipGetImageHeight | 135 | # define GdipGetImageHeight fn_GdipGetImageHeight |
| 113 | # define GdipGetImageWidth fn_GdipGetImageWidth | 136 | # define GdipGetImageWidth fn_GdipGetImageWidth |
| 114 | #endif | ||
| 115 | 137 | ||
| 116 | input.GdiplusVersion = 1; | 138 | #endif /* WINDOWSNT */ |
| 117 | input.DebugEventCallback = NULL; | ||
| 118 | input.SuppressBackgroundThread = FALSE; | ||
| 119 | input.SuppressExternalCodecs = FALSE; | ||
| 120 | 139 | ||
| 121 | status = GdiplusStartup (&token, &input, &output); | 140 | static int gdip_initialized; |
| 122 | if (status == Ok) | 141 | static bool gdiplus_started; |
| 123 | { | 142 | static ULONG_PTR token; |
| 124 | gdip_initialized = 1; | 143 | static GdiplusStartupInput input; |
| 125 | return 1; | 144 | static GdiplusStartupOutput output; |
| 126 | } | 145 | |
| 127 | else | 146 | |
| 147 | /* Initialize GDI+, return true if successful. */ | ||
| 148 | static bool | ||
| 149 | gdiplus_startup (void) | ||
| 150 | { | ||
| 151 | GpStatus status; | ||
| 152 | |||
| 153 | if (gdiplus_started) | ||
| 154 | return true; | ||
| 155 | #ifdef WINDOWSNT | ||
| 156 | if (!gdip_initialized) | ||
| 157 | gdip_initialized = gdiplus_init () ? 1 : -1; | ||
| 158 | #else | ||
| 159 | gdip_initialized = 1; | ||
| 160 | #endif | ||
| 161 | if (gdip_initialized > 0) | ||
| 128 | { | 162 | { |
| 129 | gdip_initialized = -1; | 163 | input.GdiplusVersion = 1; |
| 130 | return 0; | 164 | input.DebugEventCallback = NULL; |
| 165 | input.SuppressBackgroundThread = FALSE; | ||
| 166 | input.SuppressExternalCodecs = FALSE; | ||
| 167 | |||
| 168 | status = GdiplusStartup (&token, &input, &output); | ||
| 169 | if (status == Ok) | ||
| 170 | gdiplus_started = true; | ||
| 171 | return (status == Ok); | ||
| 131 | } | 172 | } |
| 173 | return false; | ||
| 132 | } | 174 | } |
| 133 | 175 | ||
| 176 | /* This is called from term_ntproc. */ | ||
| 134 | void | 177 | void |
| 135 | w32_gdiplus_shutdown (void) | 178 | w32_gdiplus_shutdown (void) |
| 136 | { | 179 | { |
| 137 | GdiplusShutdown (token); | 180 | if (gdiplus_started) |
| 181 | GdiplusShutdown (token); | ||
| 182 | gdiplus_started = false; | ||
| 138 | } | 183 | } |
| 139 | 184 | ||
| 185 | bool | ||
| 186 | w32_can_use_native_image_api (Lisp_Object type) | ||
| 187 | { | ||
| 188 | if (!w32_use_native_image_api) | ||
| 189 | return false; | ||
| 190 | if (!(EQ (type, Qjpeg) | ||
| 191 | || EQ (type, Qpng) | ||
| 192 | || EQ (type, Qgif) | ||
| 193 | || EQ (type, Qtiff) | ||
| 194 | || EQ (type, Qnative_image))) | ||
| 195 | { | ||
| 196 | /* GDI+ can also display BMP, Exif, ICON, WMF, and EMF images. | ||
| 197 | But we don't yet support these in image.c. */ | ||
| 198 | return false; | ||
| 199 | } | ||
| 200 | return gdiplus_startup (); | ||
| 201 | } | ||
| 140 | 202 | ||
| 141 | static double | 203 | static double |
| 142 | w32_frame_delay (GpBitmap *pBitmap, int frame) | 204 | w32_frame_delay (GpBitmap *pBitmap, int frame) |
| @@ -150,25 +212,26 @@ w32_frame_delay (GpBitmap *pBitmap, int frame) | |||
| 150 | GdipGetPropertyItemSize (pBitmap, PropertyTagFrameDelay, &size); | 212 | GdipGetPropertyItemSize (pBitmap, PropertyTagFrameDelay, &size); |
| 151 | 213 | ||
| 152 | /* Allocate a buffer to receive the property item. */ | 214 | /* Allocate a buffer to receive the property item. */ |
| 153 | propertyItem = (PropertyItem*)malloc (size); | 215 | propertyItem = malloc (size); |
| 154 | if (propertyItem != NULL) | 216 | if (propertyItem != NULL) |
| 155 | { | 217 | { |
| 156 | /* Get the property item. */ | 218 | /* Get the property item. */ |
| 157 | GdipGetPropertyItem (pBitmap, PropertyTagFrameDelay, size, propertyItem); | 219 | GdipGetPropertyItem (pBitmap, PropertyTagFrameDelay, size, propertyItem); |
| 158 | delay = ((double)propertyItem[frame].length) / 100; | 220 | delay = propertyItem[frame].length / 100.0; |
| 159 | if (delay == 0) | 221 | if (delay == 0) |
| 160 | { | 222 | { |
| 161 | /* In GIF files, unfortunately, delay is only specified for the first | 223 | /* In GIF files, unfortunately, delay is only specified for the first |
| 162 | frame. */ | 224 | frame. */ |
| 163 | delay = ((double)propertyItem[0].length) / 100; | 225 | delay = propertyItem[0].length / 100.0; |
| 164 | } | 226 | } |
| 165 | free (propertyItem); | 227 | free (propertyItem); |
| 166 | } | 228 | } |
| 167 | return delay; | 229 | return delay; |
| 168 | } | 230 | } |
| 169 | 231 | ||
| 170 | static UINT | 232 | static GpStatus |
| 171 | w32_select_active_frame (GpBitmap *pBitmap, int frame, int *nframes, double *delay) | 233 | w32_select_active_frame (GpBitmap *pBitmap, int frame, int *nframes, |
| 234 | double *delay) | ||
| 172 | { | 235 | { |
| 173 | UINT count, frameCount; | 236 | UINT count, frameCount; |
| 174 | GUID pDimensionIDs[1]; | 237 | GUID pDimensionIDs[1]; |
| @@ -181,15 +244,14 @@ w32_select_active_frame (GpBitmap *pBitmap, int frame, int *nframes, double *del | |||
| 181 | { | 244 | { |
| 182 | status = GdipImageGetFrameDimensionsList (pBitmap, pDimensionIDs, 1); | 245 | status = GdipImageGetFrameDimensionsList (pBitmap, pDimensionIDs, 1); |
| 183 | status = GdipImageGetFrameCount (pBitmap, &pDimensionIDs[0], &frameCount); | 246 | status = GdipImageGetFrameCount (pBitmap, &pDimensionIDs[0], &frameCount); |
| 184 | if ((status == Ok) && (frameCount > 1)) | 247 | if (status == Ok && frameCount > 1) |
| 185 | { | 248 | { |
| 186 | if (frame < 0 || frame >= frameCount) | 249 | if (frame < 0 || frame >= frameCount) |
| 187 | { | 250 | status = GenericError; |
| 188 | status = GenericError; | ||
| 189 | } | ||
| 190 | else | 251 | else |
| 191 | { | 252 | { |
| 192 | status = GdipImageSelectActiveFrame (pBitmap, &pDimensionIDs[0], frame); | 253 | status = GdipImageSelectActiveFrame (pBitmap, &pDimensionIDs[0], |
| 254 | frame); | ||
| 193 | *delay = w32_frame_delay (pBitmap, frame); | 255 | *delay = w32_frame_delay (pBitmap, frame); |
| 194 | *nframes = frameCount; | 256 | *nframes = frameCount; |
| 195 | } | 257 | } |
| @@ -201,9 +263,7 @@ w32_select_active_frame (GpBitmap *pBitmap, int frame, int *nframes, double *del | |||
| 201 | static ARGB | 263 | static ARGB |
| 202 | w32_image_bg_color (struct frame *f, struct image *img) | 264 | w32_image_bg_color (struct frame *f, struct image *img) |
| 203 | { | 265 | { |
| 204 | /* png_color_16 *image_bg; */ | 266 | Lisp_Object specified_bg = Fplist_get (XCDR (img->spec), QCbackground); |
| 205 | Lisp_Object specified_bg | ||
| 206 | = Fplist_get (XCDR (img->spec), QCbackground); | ||
| 207 | Emacs_Color color; | 267 | Emacs_Color color; |
| 208 | 268 | ||
| 209 | /* If the user specified a color, try to use it; if not, use the | 269 | /* If the user specified a color, try to use it; if not, use the |
| @@ -212,38 +272,34 @@ w32_image_bg_color (struct frame *f, struct image *img) | |||
| 212 | if (STRINGP (specified_bg) | 272 | if (STRINGP (specified_bg) |
| 213 | ? w32_defined_color (f, SSDATA (specified_bg), &color, false, false) | 273 | ? w32_defined_color (f, SSDATA (specified_bg), &color, false, false) |
| 214 | : (w32_query_frame_background_color (f, &color), true)) | 274 | : (w32_query_frame_background_color (f, &color), true)) |
| 215 | /* The user specified `:background', use that. */ | 275 | /* The user specified ':background', use that. */ |
| 216 | { | 276 | { |
| 217 | DWORD red = (((DWORD) color.red) & 0xff00) << 8; | 277 | DWORD red = (((DWORD) color.red) & 0xff00) << 8; |
| 218 | DWORD green = ((DWORD) color.green) & 0xff00; | 278 | DWORD green = ((DWORD) color.green) & 0xff00; |
| 219 | DWORD blue = ((DWORD) color.blue) >> 8; | 279 | DWORD blue = ((DWORD) color.blue) >> 8; |
| 220 | return red | green | blue; | 280 | return (ARGB) (red | green | blue); |
| 221 | } | 281 | } |
| 222 | return ((DWORD) 0xff000000); | 282 | return (ARGB) 0xff000000; |
| 223 | } | 283 | } |
| 224 | 284 | ||
| 225 | int | 285 | int |
| 226 | w32_load_image (struct frame *f, struct image *img, | 286 | w32_load_image (struct frame *f, struct image *img, |
| 227 | Lisp_Object spec_file, Lisp_Object spec_data) | 287 | Lisp_Object spec_file, Lisp_Object spec_data) |
| 228 | { | 288 | { |
| 229 | Emacs_Pixmap pixmap; | ||
| 230 | GpStatus status = GenericError; | 289 | GpStatus status = GenericError; |
| 231 | GpBitmap *pBitmap; | 290 | GpBitmap *pBitmap; |
| 232 | wchar_t filename[MAX_PATH]; | 291 | Lisp_Object metadata; |
| 233 | ARGB bg_color; | ||
| 234 | Lisp_Object lisp_index, metadata; | ||
| 235 | unsigned int index, nframes; | ||
| 236 | double delay; | ||
| 237 | 292 | ||
| 238 | eassert (valid_image_p (img->spec)); | 293 | eassert (valid_image_p (img->spec)); |
| 239 | 294 | ||
| 240 | /* This function only gets called if init_w32_gdiplus () was invoked. We have | 295 | /* This function only gets called if w32_gdiplus_startup was invoked |
| 241 | a valid token and GDI+ is active. */ | 296 | and succeeded. We have a valid token and GDI+ is active. */ |
| 242 | if (STRINGP (spec_file)) | 297 | if (STRINGP (spec_file)) |
| 243 | { | 298 | { |
| 244 | if (w32_unicode_filenames) | 299 | if (w32_unicode_filenames) |
| 245 | { | 300 | { |
| 246 | filename_to_utf16 (SSDATA (spec_file) , filename); | 301 | wchar_t filename[MAX_PATH]; |
| 302 | filename_to_utf16 (SSDATA (spec_file), filename); | ||
| 247 | status = GdipCreateBitmapFromFile (filename, &pBitmap); | 303 | status = GdipCreateBitmapFromFile (filename, &pBitmap); |
| 248 | } | 304 | } |
| 249 | else | 305 | else |
| @@ -254,7 +310,7 @@ w32_load_image (struct frame *f, struct image *img, | |||
| 254 | } | 310 | } |
| 255 | else if (STRINGP (spec_data)) | 311 | else if (STRINGP (spec_data)) |
| 256 | { | 312 | { |
| 257 | IStream *pStream = SHCreateMemStream ((BYTE *) SSDATA (spec_data), | 313 | IStream *pStream = SHCreateMemStream ((BYTE *) SDATA (spec_data), |
| 258 | SBYTES (spec_data)); | 314 | SBYTES (spec_data)); |
| 259 | if (pStream != NULL) | 315 | if (pStream != NULL) |
| 260 | { | 316 | { |
| @@ -266,22 +322,28 @@ w32_load_image (struct frame *f, struct image *img, | |||
| 266 | metadata = Qnil; | 322 | metadata = Qnil; |
| 267 | if (status == Ok) | 323 | if (status == Ok) |
| 268 | { | 324 | { |
| 269 | /* In multiframe pictures, select the first one */ | 325 | /* In multiframe pictures, select the first frame. */ |
| 270 | lisp_index = Fplist_get (XCDR (img->spec), QCindex); | 326 | Lisp_Object lisp_index = Fplist_get (XCDR (img->spec), QCindex); |
| 271 | index = FIXNUMP (lisp_index) ? XFIXNAT (lisp_index) : 0; | 327 | int index = FIXNATP (lisp_index) ? XFIXNAT (lisp_index) : 0; |
| 328 | int nframes; | ||
| 329 | double delay; | ||
| 272 | status = w32_select_active_frame (pBitmap, index, &nframes, &delay); | 330 | status = w32_select_active_frame (pBitmap, index, &nframes, &delay); |
| 273 | if ((status == Ok)) | 331 | if (status == Ok) |
| 274 | { | 332 | { |
| 275 | if (nframes > 1) | 333 | if (nframes > 1) |
| 276 | metadata = Fcons (Qcount, Fcons (make_fixnum (nframes), metadata)); | 334 | metadata = Fcons (Qcount, Fcons (make_fixnum (nframes), metadata)); |
| 277 | if (delay) | 335 | if (delay) |
| 278 | metadata = Fcons (Qdelay, Fcons (make_float (delay), metadata)); | 336 | metadata = Fcons (Qdelay, Fcons (make_float (delay), metadata)); |
| 279 | } | 337 | } |
| 338 | else if (status == Win32Error) /* FIXME! */ | ||
| 339 | status = Ok; | ||
| 280 | } | 340 | } |
| 281 | 341 | ||
| 282 | if (status == Ok) | 342 | if (status == Ok) |
| 283 | { | 343 | { |
| 284 | bg_color = w32_image_bg_color (f, img); | 344 | ARGB bg_color = w32_image_bg_color (f, img); |
| 345 | Emacs_Pixmap pixmap; | ||
| 346 | |||
| 285 | status = GdipCreateHBITMAPFromBitmap (pBitmap, &pixmap, bg_color); | 347 | status = GdipCreateHBITMAPFromBitmap (pBitmap, &pixmap, bg_color); |
| 286 | if (status == Ok) | 348 | if (status == Ok) |
| 287 | { | 349 | { |
diff --git a/src/w32term.c b/src/w32term.c index f19754df02c..108cb7922fb 100644 --- a/src/w32term.c +++ b/src/w32term.c | |||
| @@ -7658,6 +7658,25 @@ Windows 8. It is set to nil on Windows 9X. */); | |||
| 7658 | else | 7658 | else |
| 7659 | w32_unicode_filenames = 1; | 7659 | w32_unicode_filenames = 1; |
| 7660 | 7660 | ||
| 7661 | DEFVAR_BOOL ("w32-use-native-image-API", | ||
| 7662 | w32_use_native_image_api, | ||
| 7663 | doc: /* Non-nil means use the native MS-Windows image API to display images. | ||
| 7664 | |||
| 7665 | A value of nil means displaying images other than PBM and XBM requires | ||
| 7666 | optional supporting libraries to be installed. | ||
| 7667 | The native image API library used is GDI+ via GDIPLUS.DLL. This | ||
| 7668 | library is available only since W2K, therefore this variable is | ||
| 7669 | unconditionally set to nil on older systems. */); | ||
| 7670 | |||
| 7671 | /* For now, disabled by default, since this is an experimental feature. */ | ||
| 7672 | #if 0 && HAVE_NATIVE_IMAGE_API | ||
| 7673 | if (os_subtype == OS_9X) | ||
| 7674 | w32_use_native_image_api = 0; | ||
| 7675 | else | ||
| 7676 | w32_use_native_image_api = 1; | ||
| 7677 | #else | ||
| 7678 | w32_use_native_image_api = 0; | ||
| 7679 | #endif | ||
| 7661 | 7680 | ||
| 7662 | /* FIXME: The following variable will be (hopefully) removed | 7681 | /* FIXME: The following variable will be (hopefully) removed |
| 7663 | before Emacs 25.1 gets released. */ | 7682 | before Emacs 25.1 gets released. */ |
diff --git a/src/w32term.h b/src/w32term.h index 7ca00d0a099..8ba248013c7 100644 --- a/src/w32term.h +++ b/src/w32term.h | |||
| @@ -75,10 +75,6 @@ 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 | 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); | ||
| 82 | 78 | ||
| 83 | /* For each display (currently only one on w32), we have a structure that | 79 | /* For each display (currently only one on w32), we have a structure that |
| 84 | records information about it. */ | 80 | records information about it. */ |