diff options
author | Eli Zaretskii <eliz@gnu.org> | 2020-04-14 18:10:41 +0300 |
---|---|---|
committer | Eli Zaretskii <eliz@gnu.org> | 2020-04-14 18:10:41 +0300 |
commit | e94206aaf608a899c81bb07fe91d26439f51b3f8 (patch) | |
tree | a4a24407f1ba3d70ae192a1aad954a2bed3e91e1 | |
parent | df254a7445a86dc25d133f2d79be8096190a8b96 (diff) | |
download | emacs-e94206aaf608a899c81bb07fe91d26439f51b3f8.tar.gz |
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.
-rw-r--r-- | configure.ac | 16 | ||||
-rw-r--r-- | etc/NEWS | 5 | ||||
-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 |
8 files changed, 258 insertions, 152 deletions
diff --git a/configure.ac b/configure.ac index 41a1860493a..b0a2cc466b9 100644 --- a/configure.ac +++ b/configure.ac @@ -433,7 +433,7 @@ OPTION_DEFAULT_ON([libsystemd],[don't compile with libsystemd support]) OPTION_DEFAULT_ON([cairo],[don't compile with Cairo drawing]) OPTION_DEFAULT_ON([xml2],[don't compile with XML parsing support]) OPTION_DEFAULT_OFF([imagemagick],[compile with ImageMagick image support]) -OPTION_DEFAULT_OFF([native-image-api], [use native API's (GDI+ on Windows) for JPEG/TIFF/GIFF/PNG]) +OPTION_DEFAULT_ON([native-image-api], [use native image APIs (GDI+ on Windows)]) OPTION_DEFAULT_ON([json], [don't compile with native JSON support]) OPTION_DEFAULT_ON([xft],[don't use XFT for anti aliased fonts]) @@ -2127,7 +2127,7 @@ LIB_WSOCK32= NTLIB= CM_OBJ="cm.o" XARGS_LIMIT= -HAVE_NATIVE_IMAGE_API=no +NATIVE_IMAGE_API=no if test "${HAVE_W32}" = "yes"; then AC_DEFINE(HAVE_NTGUI, 1, [Define to use native MS Windows GUI.]) if test "$with_toolkit_scroll_bars" = "no"; then @@ -2156,12 +2156,14 @@ if test "${HAVE_W32}" = "yes"; then # the rc file), not a linker script. W32_RES_LINK="-Wl,emacs.res" else + W32_OBJ="$W32_OBJ w32.o w32console.o w32heap.o w32inevt.o w32proc.o" + dnl FIXME: This should probably be supported for Cygwin/w32 as + dnl well, but the Cygwin build needs to link against -lgdiplus if test "${with_native_image_api}" = yes; then - AC_DEFINE(HAVE_NATIVE_IMAGE_API, 1, [Define to use MS Windows GDI+ for images.]) - HAVE_NATIVE_IMAGE_API=yes - W32_NATIVE_IMAGE_API="w32image.o" + AC_DEFINE(HAVE_NATIVE_IMAGE_API, 1, [Define to use native OS APIs for images.]) + NATIVE_IMAGE_API="yes (w32)" + W32_OBJ="$W32_OBJ w32image.o" fi - W32_OBJ="$W32_OBJ w32.o w32console.o w32heap.o w32inevt.o w32proc.o $W32_NATIVE_IMAGE_API" W32_LIBS="$W32_LIBS -lwinmm -lusp10 -lgdi32 -lcomdlg32" W32_LIBS="$W32_LIBS -lmpr -lwinspool -lole32 -lcomctl32" W32_RES_LINK="\$(EMACSRES)" @@ -5710,7 +5712,7 @@ AS_ECHO([" Does Emacs use -lXaw3d? ${HAVE_XAW3D Does Emacs use cairo? ${HAVE_CAIRO} Does Emacs use -llcms2? ${HAVE_LCMS2} Does Emacs use imagemagick? ${HAVE_IMAGEMAGICK} - Does Emacs use native API for images? ${HAVE_NATIVE_IMAGE_API} + Does Emacs use native APIs for images? ${NATIVE_IMAGE_API} Does Emacs support sound? ${HAVE_SOUND} Does Emacs use -lgpm? ${HAVE_GPM} Does Emacs use -ldbus? ${HAVE_DBUS} @@ -393,6 +393,11 @@ images in JPEG, PNG, GIF and TIFF formats. This support is enabled with --with-native-image-api, which automatically disables the use of optional third party libraries for those formats. +This feature is experimental, and needs to be turned on to be used. +To turn this on, set the variable 'w32-use-native-image-API' to a +non-nil value. Please report any bugs you find while using the native +image API via "M-x report-emacs-bug". + ---------------------------------------------------------------------- This file is part of GNU Emacs. 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 /* Check that SPEC is a valid image specification for the given image type. Value is true if SPEC is valid. */ - bool (*valid_p) (Lisp_Object spec, Lisp_Object type); + bool (*valid_p) (Lisp_Object spec); /* Load IMG which is used on frame F from information contained in IMG->spec. Value is true if successful. */ @@ -807,7 +807,7 @@ valid_image_p (Lisp_Object object) { struct image_type const *type = lookup_image_type (XCAR (tail)); if (type) - return type->valid_p (object, builtin_lisp_symbol (type->type)); + return type->valid_p (object); } break; } @@ -816,7 +816,6 @@ valid_image_p (Lisp_Object object) return false; } - /* Log error message with format string FORMAT and trailing arguments. Signaling an error, e.g. when an image cannot be loaded, is not a good idea because this would interrupt redisplay, and the error @@ -1004,7 +1003,8 @@ parse_image_spec (Lisp_Object spec, struct image_keyword *keywords, break; } - if (EQ (key, QCtype) && !EQ (type, value)) + if (EQ (key, QCtype) + && !(EQ (type, value) || EQ (type, Qnative_image))) return false; } @@ -3144,12 +3144,12 @@ enum xbm_token displayed is used. */ static bool -xbm_image_p (Lisp_Object object, Lisp_Object type) +xbm_image_p (Lisp_Object object) { struct image_keyword kw[XBM_LAST]; memcpy (kw, xbm_format, sizeof kw); - if (!parse_image_spec (object, kw, XBM_LAST, type)) + if (!parse_image_spec (object, kw, XBM_LAST, Qxbm)) return 0; eassert (EQ (kw[XBM_TYPE].value, Qxbm)); @@ -3697,7 +3697,7 @@ xbm_load (struct frame *f, struct image *img) bool success_p = 0; Lisp_Object file_name; - eassert (xbm_image_p (img->spec, Qxbm)); + eassert (xbm_image_p (img->spec)); /* If IMG->spec specifies a file name, create a non-file spec from it. */ file_name = image_spec_value (img->spec, QCfile, NULL); @@ -4155,11 +4155,11 @@ xpm_valid_color_symbols_p (Lisp_Object color_symbols) /* Value is true if OBJECT is a valid XPM image specification. */ static bool -xpm_image_p (Lisp_Object object, Lisp_Object type) +xpm_image_p (Lisp_Object object) { struct image_keyword fmt[XPM_LAST]; memcpy (fmt, xpm_format, sizeof fmt); - return (parse_image_spec (object, fmt, XPM_LAST, type) + return (parse_image_spec (object, fmt, XPM_LAST, Qxpm) /* Either `:file' or `:data' must be present. */ && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1 /* Either no `:color-symbols' or it's a list of conses @@ -5883,13 +5883,13 @@ static const struct image_keyword pbm_format[PBM_LAST] = /* Return true if OBJECT is a valid PBM image specification. */ static bool -pbm_image_p (Lisp_Object object, Lisp_Object type) +pbm_image_p (Lisp_Object object) { struct image_keyword fmt[PBM_LAST]; memcpy (fmt, pbm_format, sizeof fmt); - if (!parse_image_spec (object, fmt, PBM_LAST, type)) + if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)) return 0; /* Must specify either :data or :file. */ @@ -6235,21 +6235,30 @@ pbm_load (struct frame *f, struct image *img) /*********************************************************************** NATIVE IMAGE HANDLING ***********************************************************************/ -#if defined(HAVE_NATIVE_IMAGE_API) && defined(HAVE_NTGUI) + +static bool +image_can_use_native_api (Lisp_Object type) +{ +#if HAVE_NATIVE_IMAGE_API +# ifdef HAVE_NTGUI + return w32_can_use_native_image_api (type); +# else + return false; +# endif +#else + return false; +#endif +} + +#if HAVE_NATIVE_IMAGE_API + /* * These functions are actually defined in the OS-native implementation * file. Currently, for Windows GDI+ interface, w32image.c, but other * operating systems can follow suit. */ -static bool -init_native_image_functions (void) -{ - return w32_gdiplus_startup (); -} - /* Indices of image specification fields in native format, below. */ - enum native_image_keyword_index { NATIVE_IMAGE_TYPE, @@ -6268,7 +6277,6 @@ enum native_image_keyword_index /* Vector of image_keyword structures describing the format of valid user-defined image specifications. */ - static const struct image_keyword native_image_format[] = { {":type", IMAGE_SYMBOL_VALUE, 1}, @@ -6287,12 +6295,12 @@ static const struct image_keyword native_image_format[] = /* Return true if OBJECT is a valid native API image specification. */ static bool -native_image_p (Lisp_Object object, Lisp_Object type) +native_image_p (Lisp_Object object) { struct image_keyword fmt[NATIVE_IMAGE_LAST]; memcpy (fmt, native_image_format, sizeof fmt); - if (!parse_image_spec (object, fmt, 10, type)) + if (!parse_image_spec (object, fmt, 10, Qnative_image)) return 0; /* Must specify either the :data or :file keyword. */ @@ -6302,11 +6310,17 @@ native_image_p (Lisp_Object object, Lisp_Object type) static bool native_image_load (struct frame *f, struct image *img) { + +# ifdef HAVE_NTGUI return w32_load_image (f, img, image_spec_value (img->spec, QCfile, NULL), image_spec_value (img->spec, QCdata, NULL)); +# else + return 0; +# endif } -#endif + +#endif /* HAVE_NATIVE_IMAGE_API */ /*********************************************************************** @@ -6352,12 +6366,12 @@ static const struct image_keyword png_format[PNG_LAST] = /* Return true if OBJECT is a valid PNG image specification. */ static bool -png_image_p (Lisp_Object object, Lisp_Object type) +png_image_p (Lisp_Object object) { struct image_keyword fmt[PNG_LAST]; memcpy (fmt, png_format, sizeof fmt); - if (!parse_image_spec (object, fmt, PNG_LAST, type)) + if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)) return 0; /* Must specify either the :data or :file keyword. */ @@ -7014,13 +7028,13 @@ static const struct image_keyword jpeg_format[JPEG_LAST] = /* Return true if OBJECT is a valid JPEG image specification. */ static bool -jpeg_image_p (Lisp_Object object, Lisp_Object type) +jpeg_image_p (Lisp_Object object) { struct image_keyword fmt[JPEG_LAST]; memcpy (fmt, jpeg_format, sizeof fmt); - if (!parse_image_spec (object, fmt, JPEG_LAST, type)) + if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)) return 0; /* Must specify either the :data or :file keyword. */ @@ -7590,12 +7604,12 @@ static const struct image_keyword tiff_format[TIFF_LAST] = /* Return true if OBJECT is a valid TIFF image specification. */ static bool -tiff_image_p (Lisp_Object object, Lisp_Object type) +tiff_image_p (Lisp_Object object) { struct image_keyword fmt[TIFF_LAST]; memcpy (fmt, tiff_format, sizeof fmt); - if (!parse_image_spec (object, fmt, TIFF_LAST, type)) + if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)) return 0; /* Must specify either the :data or :file keyword. */ @@ -8038,12 +8052,12 @@ gif_clear_image (struct frame *f, struct image *img) /* Return true if OBJECT is a valid GIF image specification. */ static bool -gif_image_p (Lisp_Object object, Lisp_Object type) +gif_image_p (Lisp_Object object) { struct image_keyword fmt[GIF_LAST]; memcpy (fmt, gif_format, sizeof fmt); - if (!parse_image_spec (object, fmt, GIF_LAST, type)) + if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)) return 0; /* Must specify either the :data or :file keyword. */ @@ -8650,12 +8664,12 @@ imagemagick_clear_image (struct frame *f, identify the IMAGEMAGICK format. */ static bool -imagemagick_image_p (Lisp_Object object, Lisp_Object type) +imagemagick_image_p (Lisp_Object object) { struct image_keyword fmt[IMAGEMAGICK_LAST]; memcpy (fmt, imagemagick_format, sizeof fmt); - if (!parse_image_spec (object, fmt, IMAGEMAGICK_LAST, type)) + if (!parse_image_spec (object, fmt, IMAGEMAGICK_LAST, Qimagemagick)) return 0; /* Must specify either the :data or :file keyword. */ @@ -9445,12 +9459,12 @@ static const struct image_keyword svg_format[SVG_LAST] = identify the SVG format. */ static bool -svg_image_p (Lisp_Object object, Lisp_Object type) +svg_image_p (Lisp_Object object) { struct image_keyword fmt[SVG_LAST]; memcpy (fmt, svg_format, sizeof fmt); - if (!parse_image_spec (object, fmt, SVG_LAST, type)) + if (!parse_image_spec (object, fmt, SVG_LAST, Qsvg)) return 0; /* Must specify either the :data or :file keyword. */ @@ -9913,7 +9927,7 @@ static const struct image_keyword gs_format[GS_LAST] = specification. */ static bool -gs_image_p (Lisp_Object object, Lisp_Object type) +gs_image_p (Lisp_Object object) { struct image_keyword fmt[GS_LAST]; Lisp_Object tem; @@ -9921,7 +9935,7 @@ gs_image_p (Lisp_Object object, Lisp_Object type) memcpy (fmt, gs_format, sizeof fmt); - if (!parse_image_spec (object, fmt, GS_LAST, type)) + if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)) return 0; /* Bounding box must be a list or vector containing 4 integers. */ @@ -10208,20 +10222,19 @@ static bool initialize_image_type (struct image_type const *type) { #ifdef WINDOWSNT - Lisp_Object typesym, tested; - bool (*init) (void) = type->init; + Lisp_Object typesym = builtin_lisp_symbol (type->type); #ifdef HAVE_NATIVE_IMAGE_API - if (init == init_native_image_functions) - return init(); + if (image_can_use_native_api (typesym)) + return true; #endif - typesym = builtin_lisp_symbol (type->type); - tested = Fassq (typesym, Vlibrary_cache); + Lisp_Object tested = Fassq (typesym, Vlibrary_cache); /* If we failed to load the library before, don't try again. */ if (CONSP (tested)) return !NILP (XCDR (tested)) ? true : false; + bool (*init) (void) = type->init; if (init) { bool type_valid = init (); @@ -10248,16 +10261,6 @@ static struct image_type const image_types[] = { SYMBOL_INDEX (Qsvg), svg_image_p, svg_load, image_clear_image, IMAGE_TYPE_INIT (init_svg_functions) }, #endif -#if defined HAVE_NATIVE_IMAGE_API - { SYMBOL_INDEX (Qjpeg), native_image_p, native_image_load, image_clear_image, - IMAGE_TYPE_INIT (init_native_image_functions) }, - { SYMBOL_INDEX (Qpng), native_image_p, native_image_load, image_clear_image, - IMAGE_TYPE_INIT (init_native_image_functions) }, - { SYMBOL_INDEX (Qgif), native_image_p, native_image_load, image_clear_image, - IMAGE_TYPE_INIT (init_native_image_functions) }, - { SYMBOL_INDEX (Qtiff), native_image_p, native_image_load, image_clear_image, - IMAGE_TYPE_INIT (init_native_image_functions) }, -#endif #if defined HAVE_PNG || defined HAVE_NS { SYMBOL_INDEX (Qpng), png_image_p, png_load, image_clear_image, IMAGE_TYPE_INIT (init_png_functions) }, @@ -10282,23 +10285,28 @@ static struct image_type const image_types[] = { SYMBOL_INDEX (Qpbm), pbm_image_p, pbm_load, image_clear_image }, }; +#ifdef HAVE_NATIVE_IMAGE_API +struct image_type native_image_type = + { SYMBOL_INDEX (Qnative_image), native_image_p, native_image_load, + image_clear_image }; +#endif + /* Look up image type TYPE, and return a pointer to its image_type structure. Return 0 if TYPE is not a known image type. */ static struct image_type const * lookup_image_type (Lisp_Object type) { +#ifdef HAVE_NATIVE_IMAGE_API + if (image_can_use_native_api (type)) + return &native_image_type; +#endif + for (int i = 0; i < ARRAYELTS (image_types); i++) { struct image_type const *r = &image_types[i]; if (EQ (type, builtin_lisp_symbol (r->type))) -#ifdef HAVE_NATIVE_IMAGE_API - /* We can have more than one backend for one image type. */ - if (initialize_image_type (r)) - return r; -#else return initialize_image_type (r) ? r : NULL; -#endif } return NULL; } @@ -10454,6 +10462,14 @@ non-numeric, there is no explicit limit on the size of images. */); #endif /* HAVE_NTGUI */ #endif /* HAVE_RSVG */ +#if HAVE_NATIVE_IMAGE_API + DEFSYM (Qnative_image, "native-image"); +# ifdef HAVE_NTGUI + DEFSYM (Qgdiplus, "gdiplus"); + DEFSYM (Qshlwapi, "shlwapi"); +# endif +#endif + defsubr (&Sinit_image_library); #ifdef HAVE_IMAGEMAGICK defsubr (&Simagemagick_types); diff --git a/src/w32.c b/src/w32.c index 1d2a52b6df4..80178029bd0 100644 --- a/src/w32.c +++ b/src/w32.c @@ -10226,7 +10226,7 @@ term_ntproc (int ignored) term_w32select (); -#ifdef HAVE_GDIPLUS +#if HAVE_NATIVE_IMAGE_API w32_gdiplus_shutdown (); #endif } 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 /* Optional RGBQUAD array for palette follows (see BITMAPINFO docs). */ } XImage; +struct image; +extern int w32_load_image (struct frame *f, struct image *img, + Lisp_Object spec_file, Lisp_Object spec_data); +extern bool w32_can_use_native_image_api (Lisp_Object); +extern void w32_gdiplus_shutdown (void); + #define FACE_DEFAULT (~0) 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/>. */ #include "lisp.h" #include "dispextern.h" #define COBJMACROS +#ifdef MINGW_W64 +/* FIXME: Do we need to include objidl.h? */ #include <objidl.h> +#endif #include <wtypes.h> #include <gdiplus.h> #include <shlwapi.h> @@ -32,53 +35,39 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include "frame.h" #include "coding.h" -/*#define LINK_GDIPLUS_STATICALLY 1*/ +#ifdef WINDOWSNT -#ifndef LINK_GDIPLUS_STATICALLY -DEF_DLL_FN (GpStatus, GdiplusStartup, (ULONG_PTR *, GdiplusStartupInput *, GdiplusStartupOutput *)); +DEF_DLL_FN (GpStatus, GdiplusStartup, + (ULONG_PTR *, GdiplusStartupInput *, GdiplusStartupOutput *)); DEF_DLL_FN (VOID, GdiplusShutdown, (ULONG_PTR)); -DEF_DLL_FN (GpStatus, GdipGetPropertyItemSize, (GpImage *, PROPID, UINT *)); -DEF_DLL_FN (GpStatus, GdipGetPropertyItem, (GpImage *, PROPID, UINT, PropertyItem *)); +DEF_DLL_FN (GpStatus, GdipGetPropertyItemSize, + (GpImage *, PROPID, UINT *)); +DEF_DLL_FN (GpStatus, GdipGetPropertyItem, + (GpImage *, PROPID, UINT, PropertyItem *)); DEF_DLL_FN (GpStatus, GdipImageGetFrameDimensionsCount, (GpImage *, UINT *)); -DEF_DLL_FN (GpStatus, GdipImageGetFrameDimensionsList, (GpImage *, GUID *, UINT)); -DEF_DLL_FN (GpStatus, GdipImageGetFrameCount, (GpImage *, GDIPCONST GUID *, UINT *)); -DEF_DLL_FN (GpStatus, GdipImageSelectActiveFrame, (GpImage*, GDIPCONST GUID *, UINT)); +DEF_DLL_FN (GpStatus, GdipImageGetFrameDimensionsList, + (GpImage *, GUID *, UINT)); +DEF_DLL_FN (GpStatus, GdipImageGetFrameCount, + (GpImage *, GDIPCONST GUID *, UINT *)); +DEF_DLL_FN (GpStatus, GdipImageSelectActiveFrame, + (GpImage*, GDIPCONST GUID *, UINT)); DEF_DLL_FN (GpStatus, GdipCreateBitmapFromFile, (WCHAR *, GpBitmap **)); DEF_DLL_FN (GpStatus, GdipCreateBitmapFromStream, (IStream *, GpBitmap **)); DEF_DLL_FN (IStream *, SHCreateMemStream, (const BYTE *pInit, UINT cbInit)); -DEF_DLL_FN (GpStatus, GdipCreateHBITMAPFromBitmap, (GpBitmap *, HBITMAP *, ARGB)); +DEF_DLL_FN (GpStatus, GdipCreateHBITMAPFromBitmap, + (GpBitmap *, HBITMAP *, ARGB)); DEF_DLL_FN (GpStatus, GdipDisposeImage, (GpImage *)); DEF_DLL_FN (GpStatus, GdipGetImageHeight, (GpImage *, UINT *)); DEF_DLL_FN (GpStatus, GdipGetImageWidth, (GpImage *, UINT *)); -#endif - -static int gdip_initialized = 0; -static ULONG_PTR token; -static GdiplusStartupInput input; -static GdiplusStartupOutput output; -bool -w32_gdiplus_startup (void) +static bool +gdiplus_init (void) { HANDLE gdiplus_lib, shlwapi_lib; - GpStatus status; - if (gdip_initialized < 0) - return 0; - else if (gdip_initialized) - return 1; - -#ifndef LINK_GDIPLUS_STATICALLY - DEFSYM (Qgdiplus, "gdiplus"); - DEFSYM (Qshlwapi, "shlwapi"); - if (!(gdiplus_lib = w32_delayed_load (Qgdiplus))) { - gdip_initialized = -1; - return 0; - } - if (!(shlwapi_lib = w32_delayed_load (Qshlwapi))) { - gdip_initialized = -1; - return 0; - } + if (!((gdiplus_lib = w32_delayed_load (Qgdiplus)) + && (shlwapi_lib = w32_delayed_load (Qshlwapi)))) + return false; LOAD_DLL_FN (gdiplus_lib, GdiplusStartup); LOAD_DLL_FN (gdiplus_lib, GdiplusShutdown); @@ -94,7 +83,41 @@ w32_gdiplus_startup (void) LOAD_DLL_FN (gdiplus_lib, GdipDisposeImage); LOAD_DLL_FN (gdiplus_lib, GdipGetImageHeight); LOAD_DLL_FN (gdiplus_lib, GdipGetImageWidth); - LOAD_DLL_FN (shlwapi_lib, SHCreateMemStream); + /* LOAD_DLL_FN (shlwapi_lib, SHCreateMemStream); */ + + /* The following terrible kludge is required to use native image API + on Windows before Vista, because SHCreateMemStream was not + exported by name in those versions, only by ordinal number. */ + fn_SHCreateMemStream = + (W32_PFN_SHCreateMemStream) get_proc_addr (shlwapi_lib, + "SHCreateMemStream"); + if (!fn_SHCreateMemStream) + { + fn_SHCreateMemStream = + (W32_PFN_SHCreateMemStream) get_proc_addr (shlwapi_lib, + MAKEINTRESOURCEA (12)); + if (!fn_SHCreateMemStream) + return false; + } + + return true; +} + +# undef GdiplusStartup +# undef GdiplusShutdown +# undef GdipGetPropertyItemSize +# undef GdipGetPropertyItem +# undef GdipImageGetFrameDimensionsCount +# undef GdipImageGetFrameDimensionsList +# undef GdipImageGetFrameCount +# undef GdipImageSelectActiveFrame +# undef GdipCreateBitmapFromFile +# undef GdipCreateBitmapFromStream +# undef SHCreateMemStream +# undef GdipCreateHBITMAPFromBitmap +# undef GdipDisposeImage +# undef GdipGetImageHeight +# undef GdipGetImageWidth # define GdiplusStartup fn_GdiplusStartup # define GdiplusShutdown fn_GdiplusShutdown @@ -111,32 +134,71 @@ w32_gdiplus_startup (void) # define GdipDisposeImage fn_GdipDisposeImage # define GdipGetImageHeight fn_GdipGetImageHeight # define GdipGetImageWidth fn_GdipGetImageWidth -#endif - input.GdiplusVersion = 1; - input.DebugEventCallback = NULL; - input.SuppressBackgroundThread = FALSE; - input.SuppressExternalCodecs = FALSE; +#endif /* WINDOWSNT */ - status = GdiplusStartup (&token, &input, &output); - if (status == Ok) - { - gdip_initialized = 1; - return 1; - } - else +static int gdip_initialized; +static bool gdiplus_started; +static ULONG_PTR token; +static GdiplusStartupInput input; +static GdiplusStartupOutput output; + + +/* Initialize GDI+, return true if successful. */ +static bool +gdiplus_startup (void) +{ + GpStatus status; + + if (gdiplus_started) + return true; +#ifdef WINDOWSNT + if (!gdip_initialized) + gdip_initialized = gdiplus_init () ? 1 : -1; +#else + gdip_initialized = 1; +#endif + if (gdip_initialized > 0) { - gdip_initialized = -1; - return 0; + input.GdiplusVersion = 1; + input.DebugEventCallback = NULL; + input.SuppressBackgroundThread = FALSE; + input.SuppressExternalCodecs = FALSE; + + status = GdiplusStartup (&token, &input, &output); + if (status == Ok) + gdiplus_started = true; + return (status == Ok); } + return false; } +/* This is called from term_ntproc. */ void w32_gdiplus_shutdown (void) { - GdiplusShutdown (token); + if (gdiplus_started) + GdiplusShutdown (token); + gdiplus_started = false; } +bool +w32_can_use_native_image_api (Lisp_Object type) +{ + if (!w32_use_native_image_api) + return false; + if (!(EQ (type, Qjpeg) + || EQ (type, Qpng) + || EQ (type, Qgif) + || EQ (type, Qtiff) + || EQ (type, Qnative_image))) + { + /* GDI+ can also display BMP, Exif, ICON, WMF, and EMF images. + But we don't yet support these in image.c. */ + return false; + } + return gdiplus_startup (); +} static double w32_frame_delay (GpBitmap *pBitmap, int frame) @@ -150,25 +212,26 @@ w32_frame_delay (GpBitmap *pBitmap, int frame) GdipGetPropertyItemSize (pBitmap, PropertyTagFrameDelay, &size); /* Allocate a buffer to receive the property item. */ - propertyItem = (PropertyItem*)malloc (size); + propertyItem = malloc (size); if (propertyItem != NULL) { /* Get the property item. */ GdipGetPropertyItem (pBitmap, PropertyTagFrameDelay, size, propertyItem); - delay = ((double)propertyItem[frame].length) / 100; + delay = propertyItem[frame].length / 100.0; if (delay == 0) { /* In GIF files, unfortunately, delay is only specified for the first frame. */ - delay = ((double)propertyItem[0].length) / 100; + delay = propertyItem[0].length / 100.0; } free (propertyItem); } return delay; } -static UINT -w32_select_active_frame (GpBitmap *pBitmap, int frame, int *nframes, double *delay) +static GpStatus +w32_select_active_frame (GpBitmap *pBitmap, int frame, int *nframes, + double *delay) { UINT count, frameCount; GUID pDimensionIDs[1]; @@ -181,15 +244,14 @@ w32_select_active_frame (GpBitmap *pBitmap, int frame, int *nframes, double *del { status = GdipImageGetFrameDimensionsList (pBitmap, pDimensionIDs, 1); status = GdipImageGetFrameCount (pBitmap, &pDimensionIDs[0], &frameCount); - if ((status == Ok) && (frameCount > 1)) + if (status == Ok && frameCount > 1) { if (frame < 0 || frame >= frameCount) - { - status = GenericError; - } + status = GenericError; else { - status = GdipImageSelectActiveFrame (pBitmap, &pDimensionIDs[0], frame); + status = GdipImageSelectActiveFrame (pBitmap, &pDimensionIDs[0], + frame); *delay = w32_frame_delay (pBitmap, frame); *nframes = frameCount; } @@ -201,9 +263,7 @@ w32_select_active_frame (GpBitmap *pBitmap, int frame, int *nframes, double *del static ARGB w32_image_bg_color (struct frame *f, struct image *img) { - /* png_color_16 *image_bg; */ - Lisp_Object specified_bg - = Fplist_get (XCDR (img->spec), QCbackground); + Lisp_Object specified_bg = Fplist_get (XCDR (img->spec), QCbackground); Emacs_Color color; /* 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) if (STRINGP (specified_bg) ? w32_defined_color (f, SSDATA (specified_bg), &color, false, false) : (w32_query_frame_background_color (f, &color), true)) - /* The user specified `:background', use that. */ + /* The user specified ':background', use that. */ { DWORD red = (((DWORD) color.red) & 0xff00) << 8; DWORD green = ((DWORD) color.green) & 0xff00; DWORD blue = ((DWORD) color.blue) >> 8; - return red | green | blue; + return (ARGB) (red | green | blue); } - return ((DWORD) 0xff000000); + return (ARGB) 0xff000000; } int w32_load_image (struct frame *f, struct image *img, Lisp_Object spec_file, Lisp_Object spec_data) { - Emacs_Pixmap pixmap; GpStatus status = GenericError; GpBitmap *pBitmap; - wchar_t filename[MAX_PATH]; - ARGB bg_color; - Lisp_Object lisp_index, metadata; - unsigned int index, nframes; - double delay; + Lisp_Object metadata; eassert (valid_image_p (img->spec)); - /* This function only gets called if init_w32_gdiplus () was invoked. We have - a valid token and GDI+ is active. */ + /* This function only gets called if w32_gdiplus_startup was invoked + and succeeded. We have a valid token and GDI+ is active. */ if (STRINGP (spec_file)) { if (w32_unicode_filenames) { - filename_to_utf16 (SSDATA (spec_file) , filename); + wchar_t filename[MAX_PATH]; + filename_to_utf16 (SSDATA (spec_file), filename); status = GdipCreateBitmapFromFile (filename, &pBitmap); } else @@ -254,7 +310,7 @@ w32_load_image (struct frame *f, struct image *img, } else if (STRINGP (spec_data)) { - IStream *pStream = SHCreateMemStream ((BYTE *) SSDATA (spec_data), + IStream *pStream = SHCreateMemStream ((BYTE *) SDATA (spec_data), SBYTES (spec_data)); if (pStream != NULL) { @@ -266,22 +322,28 @@ w32_load_image (struct frame *f, struct image *img, metadata = Qnil; if (status == Ok) { - /* In multiframe pictures, select the first one */ - lisp_index = Fplist_get (XCDR (img->spec), QCindex); - index = FIXNUMP (lisp_index) ? XFIXNAT (lisp_index) : 0; + /* In multiframe pictures, select the first frame. */ + Lisp_Object lisp_index = Fplist_get (XCDR (img->spec), QCindex); + int index = FIXNATP (lisp_index) ? XFIXNAT (lisp_index) : 0; + int nframes; + double delay; status = w32_select_active_frame (pBitmap, index, &nframes, &delay); - if ((status == Ok)) + if (status == Ok) { if (nframes > 1) metadata = Fcons (Qcount, Fcons (make_fixnum (nframes), metadata)); if (delay) metadata = Fcons (Qdelay, Fcons (make_float (delay), metadata)); } + else if (status == Win32Error) /* FIXME! */ + status = Ok; } if (status == Ok) { - bg_color = w32_image_bg_color (f, img); + ARGB bg_color = w32_image_bg_color (f, img); + Emacs_Pixmap pixmap; + status = GdipCreateHBITMAPFromBitmap (pBitmap, &pixmap, bg_color); if (status == Ok) { 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. */); else w32_unicode_filenames = 1; + DEFVAR_BOOL ("w32-use-native-image-API", + w32_use_native_image_api, + doc: /* Non-nil means use the native MS-Windows image API to display images. + +A value of nil means displaying images other than PBM and XBM requires +optional supporting libraries to be installed. +The native image API library used is GDI+ via GDIPLUS.DLL. This +library is available only since W2K, therefore this variable is +unconditionally set to nil on older systems. */); + + /* For now, disabled by default, since this is an experimental feature. */ +#if 0 && HAVE_NATIVE_IMAGE_API + if (os_subtype == OS_9X) + w32_use_native_image_api = 0; + else + w32_use_native_image_api = 1; +#else + w32_use_native_image_api = 0; +#endif /* FIXME: The following variable will be (hopefully) removed 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 { extern void w32_regenerate_palette (struct frame *f); extern void w32_fullscreen_rect (HWND hwnd, int fsmode, RECT normal, RECT *rect); -extern int w32_load_image (struct frame *f, struct image *img, - Lisp_Object spec_file, Lisp_Object spec_data); -extern bool w32_gdiplus_startup (void); -extern void w32_gdiplus_shutdown (void); /* For each display (currently only one on w32), we have a structure that records information about it. */ |