caldwell / build-emacs

Build scripts for www.emacsformacosx.com
http://www.emacsformacosx.com/about
GNU General Public License v3.0
364 stars 61 forks source link

Invalid Image type 'svg' when launching Emacs #126

Closed kongotania closed 1 year ago

kongotania commented 1 year ago

I have downloaded emacs for macOS x. And have the error Invalid Image when starting

Steps to reproduce: 1) Download https://emacsformacosx.com/emacs-builds/Emacs-28.2-universal.dmg Open Emacs-28.2-universal.dmg and install start Emacs no startup screen -> Invalid Image type 'svg'

2) Emacs Menu -> Help -> About Emacs Invalid Image type 'svg'

3) Open SVG image and will show the same error

I had also tried with the nightly release, and same problem.

Apple Macbook Air M1 macOS Ventura 13.0

suliveevil commented 1 year ago

I have the same problem on same hardware and macOS 13.0.1(22A400)

emacs -Q

M-x ielm

*** Welcome to IELM ***  Type (describe-mode) or press C-h m for help.
ELISP> (image-type-available-p 'svg)
t

Emacs-2022-11-23_00-10-09-5e8c62ffcae473b89e268e0081d4041fb19abef7-universal Emacs-2022-11-16_00-09-19-60f2bb862f834fcb580d839ac79b30a8b4cd4167-universal Emacs-2022-11-13_00-09-16-756373a772c2c096bad1b26d7e46fa6144086ce1-universal Emacs-28.2-universal Emacs-pretest-28.1.91-universal

caldwell commented 1 year ago

I did a bunch of emacs debugger stuff last night and this morning and I think I tracked the problem down:

ELISP> image-types
(png gif tiff jpeg xpm xbm pbm)

No svg there!

Interestingly, the docs for image-types say:

List of potentially supported image types.
Each element of the list is a symbol for an image type, like ‘jpeg’ or ‘png’.
To check whether it is really supported, use ‘image-type-available-p’.

but the actual image code (image-type in image.el, look at it with: C-h f image-type RET or here) says:

 (when (and (not (eq type 'image-convert))
             (not (memq type (and (boundp 'image-types) image-types))))

So despite it just being "potential" they actually require it to be in that list. That list gets built in C code (image.c):

#if defined (HAVE_RSVG)
  DEFSYM (Qsvg, "svg");

So they're only defining it when it's being build with rsvg. These builds don't have that, so it's not in the list. But then why does image-type-available-p say it's available? Well, that calls a C function in the images.c file called init-image-library, which just calls another C function named lookup_image_type:

static struct image_type const *
lookup_image_type (Lisp_Object type)
{
#if 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)))
    return initialize_image_type (r) ? r : NULL;
    }
  return NULL;
}

If you ignore the ifdef for a second, that code just loops through the same image-types variable (the one that doesn't have svg in it) and sees if it can really instantiate it. So that part can't be the issue—it has to be that ifdef. So let's look at image_can_use_native_api:

#if HAVE_NATIVE_IMAGE_API
static bool
image_can_use_native_api (Lisp_Object type)
{
# ifdef HAVE_NTGUI
  return w32_can_use_native_image_api (type);
# elif defined HAVE_NS
  return ns_can_use_native_image_api (type);
# else
  return false;
# endif
}

Interesting, so on NS (NextStep, ie macOS (emacs is old 🙂, plus it actually works with GNUstep, Gnu's free-software nextstep/cocoa api clone)) they call an image loader from the OS instead of using various external libraries. ns_can_use_native_image_api is in nsimage.m and has this in it (in the NS_IMPL_COCOA section):

  else if (EQ (type, Qsvg))
    imageType = @"public.svg-image";

Aha! So the native image loader says they support SVG, but the svg symbol only gets added if we compile with rsvg. That's a straight up bug in Emacs. And indeed, if you look at where they add PNG, JPEG, etc. to image-types (just above the svg code), you'll notice that they all check for either the external library or the native library:

#if defined (HAVE_JPEG) || defined (HAVE_NATIVE_IMAGE_API)
  DEFSYM (Qjpeg, "jpeg");
  add_image_type (Qjpeg);
#endif

#if defined (HAVE_TIFF) || defined (HAVE_NATIVE_IMAGE_API)
  DEFSYM (Qtiff, "tiff");
  add_image_type (Qtiff);
#endif

#if defined (HAVE_GIF) || defined (HAVE_NATIVE_IMAGE_API)
  DEFSYM (Qgif, "gif");
  add_image_type (Qgif);
#endif

#if defined (HAVE_PNG) || defined (HAVE_NATIVE_IMAGE_API)
  DEFSYM (Qpng, "png");
  add_image_type (Qpng);
#endif

So to me it looks like they should have also had that || defined (HAVE_NATIVE_IMAGE_API) in the SVG section (it might have to be || (defined (HAVE_NATIVE_IMAGE_API) && defined (NS_IMPL_COCOA)), since that ns_can_use_native_image_api function has a section for the GNUstep support).

We can verify this is the problem by doing just adding the svg symbol to the image-types list ourself:

ELISP> (add-to-list 'image-types 'svg)
(svg png gif tiff jpeg xpm xbm pbm)

ELISP> (display-splash-screen)
#<buffer *GNU Emacs*>

Woohoo! 🥳

Here'e the kicker: They've already fixed this. If you look at the same section of code in the emacs-29 branch you'll see they added this to the svg section:

#elif defined HAVE_NATIVE_IMAGE_API         \
  && ((defined HAVE_NS && defined NS_IMPL_COCOA)    \
      || defined HAVE_HAIKU)
  DEFSYM (Qsvg, "svg");

  /* On Haiku, the SVG translator may not be installed.  */
  if (image_can_use_native_api (Qsvg))
    add_image_type (Qsvg);
#endif

And there we see them add the svg symbol if it's a mac. Fwew.

But that's kind of cold comfort because though they are working on releasing Emacs 29, it hasn't happened yet. And they don't move super fast—it's probably several months out, at least (there still hasn't even been a pre-test release).

In the meantime, there's not much I can do about this. My policy is to not patch the Emacs source (C or Lisp) and just build the project as is, packing it up so the binary can run on as many OS versions as I can reasonable handle.

The workaround is pretty simple though. Add this to your .emacs or .emacs.d/init.el:

(add-to-list 'image-types 'svg)

and voila, the splash screen works (and hopefully other places that might use svgs).

BTW @suliveevil , thanks for showing me ielm—I've just been using *scratch* for years without knowing that existed! I have been craving a repl with command history…

kongotania commented 1 year ago

add (add-to-list 'image-types 'svg) to my .emacs and know is working, I can show the emacs startup script and svg images.