]> git.eshelyaron.com Git - emacs.git/commitdiff
Make use of MS-Windows native image API be selectable at run time
authorEli Zaretskii <eliz@gnu.org>
Tue, 14 Apr 2020 15:10:41 +0000 (18:10 +0300)
committerEli Zaretskii <eliz@gnu.org>
Tue, 14 Apr 2020 15:10:41 +0000 (18:10 +0300)
* 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.

configure.ac
etc/NEWS
src/image.c
src/w32.c
src/w32gui.h
src/w32image.c
src/w32term.c
src/w32term.h

index 41a1860493acd5b35d6c8eaece3ef7431f48f6cc..b0a2cc466b9bf195f3076c7d2e40d19ecfe76589 100644 (file)
@@ -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}
index 7ed24e3f85be384e07fda95ad8843d65768c7038..1bfaf655b1d709feec94c1e516119857dbece79c 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -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".
+
 \f
 ----------------------------------------------------------------------
 This file is part of GNU Emacs.
index ff2d12fa1a1e893c73708e79ae92c52310c7b89a..4ef3e9d3e4c86f87cf12e313e1f34477bcfe01a1 100644 (file)
@@ -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 */
 
 \f
 /***********************************************************************
@@ -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);
index 1d2a52b6df435ffebaded1f2709b91bc3b967fda..80178029bd0940bb3dd495f908a119f276f696ae 100644 (file)
--- 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
 }
index 5cc64287291462ecd5c08016062e835cd2ac7d0b..dfec1f086171afb2c83810b9913152167bef0422 100644 (file)
@@ -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;
index fe32660f712c485900ff9c2ff4737edd2632dd7c..6a3e37ce0eeb391ff4d16415497ddce45c2afcab 100644 (file)
@@ -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)
         {
index f19754df02c5bbcc171db8ba32c3c875589e80b1..108cb7922fb5bfbf46b6b61727edd220c917b759 100644 (file)
@@ -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.  */
index 7ca00d0a099c9922d37d1073196e13e5adfcf848..8ba248013c77065259141fb7af418b8f01e63e11 100644 (file)
@@ -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);
 \f
 /* For each display (currently only one on w32), we have a structure that
    records information about it.  */