? emacs_svg.patch Index: configure.in =================================================================== RCS file: /sources/emacs/emacs/configure.in,v retrieving revision 1.459 diff -u -p -r1.459 configure.in --- configure.in 26 Jul 2007 05:26:01 -0000 1.459 +++ configure.in 20 Aug 2007 08:47:43 -0000 @@ -110,10 +110,12 @@ AC_ARG_WITH(png, [ --with-png use -lpng for displaying PNG images]) AC_ARG_WITH(gpm, [ --with-gpm use -lgpm for mouse support on a GNU/Linux console]) +AC_ARG_WITH(rsvg, +[ --with-rsvg use -lrsvg-2 for displaying SVG images]) AC_ARG_WITH(gtk, [ --with-gtk use GTK (same as --with-x-toolkit=gtk)]) AC_ARG_WITH(pkg-config-prog, -[ --with-pkg-config-prog Path to pkg-config to use for finding GTK]) +[ --with-pkg-config-prog Path to pkg-config to use for finding GTK and librsvg]) AC_ARG_WITH(toolkit-scroll-bars, [ --without-toolkit-scroll-bars don't use Motif or Xaw3d scroll bars]) @@ -2122,6 +2124,32 @@ fail; fi fi +### Use -lrsvg-2 if available, unless `--with-rsvg=no' is specified. +HAVE_RSVG=no +if test "${HAVE_X11}" = "yes"; then + if test "${with_rsvg}" != "no"; then + dnl Check if `--with-pkg-config-prog' has been given. + if test "X${with_pkg_config_prog}" != X; then + PKG_CONFIG="${with_pkg_config_prog}" + fi + + RSVG_REQUIRED=2.0.0 + RSVG_MODULE="librsvg-2.0 >= $RSVG_REQUIRED" + + PKG_CHECK_MODULES(RSVG, $RSVG_MODULE, :, :) + AC_SUBST(RSVG_CFLAGS) + AC_SUBST(RSVG_LIBS) + + if test ".${RSVG_CFLAGS}" != "."; then + HAVE_RSVG=yes + AC_DEFINE(HAVE_RSVG, 1, [Define to 1 if using librsvg.]) + CFLAGS="$CFLAGS $RSVG_CFLAGS" + LIBS="$RSVG_LIBS $LIBS" + fi + fi +fi + + HAVE_GTK=no if test "${with_gtk}" = "yes" && test "$USE_X_TOOLKIT" = "gtk"; then USE_X_TOOLKIT=none @@ -3362,6 +3390,7 @@ echo " Does Emacs use -ljpeg? echo " Does Emacs use -ltiff? ${HAVE_TIFF}" echo " Does Emacs use a gif library? ${HAVE_GIF} $ac_gif_lib_name" echo " Does Emacs use -lpng? ${HAVE_PNG}" +echo " Does Emacs use -lrsvg-2? ${HAVE_RSVG}" echo " Does Emacs use -lgpm? ${HAVE_GPM}" echo " Does Emacs use X toolkit scroll bars? ${USE_TOOLKIT_SCROLL_BARS}" echo Index: lisp/image-file.el =================================================================== RCS file: /sources/emacs/emacs/lisp/image-file.el,v retrieving revision 1.29 diff -u -p -r1.29 image-file.el --- lisp/image-file.el 26 Jul 2007 05:26:26 -0000 1.29 +++ lisp/image-file.el 20 Aug 2007 08:48:30 -0000 @@ -39,7 +39,7 @@ ;;;###autoload (defcustom image-file-name-extensions - '("png" "jpeg" "jpg" "gif" "tiff" "tif" "xbm" "xpm" "pbm" "pgm" "ppm" "pnm") + '("png" "jpeg" "jpg" "gif" "tiff" "tif" "xbm" "xpm" "pbm" "pgm" "ppm" "pnm" "svg") "*A list of image-file filename extensions. Filenames having one of these extensions are considered image files, in addition to those matching `image-file-name-regexps'. Index: lisp/image.el =================================================================== RCS file: /sources/emacs/emacs/lisp/image.el,v retrieving revision 1.72 diff -u -p -r1.72 image.el --- lisp/image.el 26 Jul 2007 05:26:26 -0000 1.72 +++ lisp/image.el 20 Aug 2007 08:48:30 -0000 @@ -43,7 +43,8 @@ static char \\1_bits" . xbm) ("\\`\\(?:MM\0\\*\\|II\\*\0\\)" . tiff) ("\\`[\t\n\r ]*%!PS" . postscript) - ("\\`\xff\xd8" . (image-jpeg-p . jpeg))) + ("\\`\xff\xd8" . (image-jpeg-p . jpeg)) + ("\\`<\\?xml " . svg)) "Alist of (REGEXP . IMAGE-TYPE) pairs used to auto-detect image types. When the first bytes of an image file match REGEXP, it is assumed to be of image type IMAGE-TYPE if IMAGE-TYPE is a symbol. If not a symbol, Index: src/Makefile.in =================================================================== RCS file: /sources/emacs/emacs/src/Makefile.in,v retrieving revision 1.346 diff -u -p -r1.346 Makefile.in --- src/Makefile.in 26 Jul 2007 05:27:47 -0000 1.346 +++ src/Makefile.in 20 Aug 2007 08:49:46 -0000 @@ -281,7 +281,7 @@ TOOLKIT_DEFINES = /* C_SWITCH_X_SITE must come before C_SWITCH_X_MACHINE and C_SWITCH_X_SYSTEM since it may have -I options that should override those two. */ -ALL_CFLAGS=-Demacs -DHAVE_CONFIG_H $(TOOLKIT_DEFINES) $(MYCPPFLAGS) -I. -I${srcdir} C_SWITCH_MACHINE C_SWITCH_SYSTEM C_SWITCH_SITE C_SWITCH_X_SITE C_SWITCH_X_MACHINE C_SWITCH_X_SYSTEM C_SWITCH_SYSTEM_TEMACS ${CFLAGS_SOUND} ${CFLAGS} +ALL_CFLAGS=-Demacs -DHAVE_CONFIG_H $(TOOLKIT_DEFINES) $(MYCPPFLAGS) -I. -I${srcdir} C_SWITCH_MACHINE C_SWITCH_SYSTEM C_SWITCH_SITE @RSVG_CFLAGS@ C_SWITCH_X_SITE C_SWITCH_X_MACHINE C_SWITCH_X_SYSTEM C_SWITCH_SYSTEM_TEMACS ${CFLAGS_SOUND} ${CFLAGS} .c.o: $(CC) -c $(CPPFLAGS) $(ALL_CFLAGS) $< @@ -450,7 +450,7 @@ XFT_LIBS=@XFT_LIBS@ /* LD_SWITCH_X_DEFAULT comes after everything else that specifies options for where to find X libraries, but before those libraries. */ X11_LDFLAGS = LD_SWITCH_X_SITE LD_SWITCH_X_DEFAULT -LIBX= $(LIBXMENU) $(X11_LDFLAGS) $(LIBXT) LIBTIFF LIBJPEG LIBPNG LIBGIF LIBXPM LIB_X11_LIB LIBX11_MACHINE LIBX11_SYSTEM $(XFT_LIBS) +LIBX= $(LIBXMENU) $(X11_LDFLAGS) $(LIBXT) LIBTIFF LIBJPEG LIBPNG LIBGIF LIBXPM @RSVG_LIBS@ LIB_X11_LIB LIBX11_MACHINE LIBX11_SYSTEM $(XFT_LIBS) #else /* not HAVE_X11 */ LIBX= $(LIBXMENU) LD_SWITCH_X_SITE -lX10 LIBX10_MACHINE LIBX10_SYSTEM #endif /* not HAVE_X11 */ Index: src/image.c =================================================================== RCS file: /sources/emacs/emacs/src/image.c,v retrieving revision 1.77 diff -u -p -r1.77 image.c --- src/image.c 7 Aug 2007 16:25:26 -0000 1.77 +++ src/image.c 20 Aug 2007 08:49:50 -0000 @@ -8199,6 +8199,329 @@ gif_load (f, img) #endif /* HAVE_GIF */ + +/*********************************************************************** + SVG + ***********************************************************************/ + +#if defined (HAVE_RSVG) + +/* Function prototypes. */ + +static int svg_image_p P_ ((Lisp_Object object)); +static int svg_load P_ ((struct frame *f, struct image *img)); + +static int svg_load_image P_ ((struct frame *, struct image *, + unsigned char *, unsigned int)); + +/* The symbol `svg' identifying images of this type. */ + +Lisp_Object Qsvg; + +/* Indices of image specification fields in svg_format, below. */ + +enum svg_keyword_index +{ + SVG_TYPE, + SVG_DATA, + SVG_FILE, + SVG_ASCENT, + SVG_MARGIN, + SVG_RELIEF, + SVG_ALGORITHM, + SVG_HEURISTIC_MASK, + SVG_MASK, + SVG_BACKGROUND, + SVG_LAST +}; + +/* Vector of image_keyword structures describing the format + of valid user-defined image specifications. */ + +static struct image_keyword svg_format[SVG_LAST] = +{ + {":type", IMAGE_SYMBOL_VALUE, 1}, + {":data", IMAGE_STRING_VALUE, 0}, + {":file", IMAGE_STRING_VALUE, 0}, + {":ascent", IMAGE_ASCENT_VALUE, 0}, + {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, + {":relief", IMAGE_INTEGER_VALUE, 0}, + {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":background", IMAGE_STRING_OR_NIL_VALUE, 0} +}; + +/* Structure describing the image type `svg'. Its the same type of + structure defined for all image formats, handled by emacs image + functions. See struct image_type in dispextern.h. */ + +static struct image_type svg_type = +{ + /* An identifier showing that this is an image structure for the SVG format. */ + &Qsvg, + /* Handle to a function that can be used to identify a SVG file. */ + svg_image_p, + /* Handle to function used to load a SVG file. */ + svg_load, + /* Handle to function to free sresources for SVG. */ + x_clear_image, + /* An internal field to link to the next image type in a list of + image types, will be filled in when registering the format. */ + NULL +}; + + +/* Return non-zero if OBJECT is a valid SVG image specification. Do + this by calling parse_image_spec and supplying the keywords that + identify the SVG format. */ + +static int +svg_image_p (object) + Lisp_Object object; +{ + struct image_keyword fmt[SVG_LAST]; + bcopy (svg_format, fmt, sizeof fmt); + + if (!parse_image_spec (object, fmt, SVG_LAST, Qsvg)) + return 0; + + /* Must specify either the :data or :file keyword. */ + return fmt[SVG_FILE].count + fmt[SVG_DATA].count == 1; +} + +#include + +/* TO DO: define DEF_IMGLIB_FN here. This macro is used to handle +loading of dynamic link library functions for various OS:es. +Currently only librsvg2 is supported, which is only available for X, +so its not strictly necessary yet. The current code is thought to be +compatible with this scheme because of the defines below, should +librsvg2 become available on more plattforms. */ + +#define fn_rsvg_handle_new rsvg_handle_new +#define fn_rsvg_handle_set_size_callback rsvg_handle_set_size_callback +#define fn_rsvg_handle_write rsvg_handle_write +#define fn_rsvg_handle_close rsvg_handle_close +#define fn_rsvg_handle_get_pixbuf rsvg_handle_get_pixbuf +#define fn_rsvg_handle_free rsvg_handle_free + +#define fn_gdk_pixbuf_get_width gdk_pixbuf_get_width +#define fn_gdk_pixbuf_get_height gdk_pixbuf_get_height +#define fn_gdk_pixbuf_get_pixels gdk_pixbuf_get_pixels +#define fn_gdk_pixbuf_get_rowstride gdk_pixbuf_get_rowstride +#define fn_gdk_pixbuf_get_colorspace gdk_pixbuf_get_colorspace +#define fn_gdk_pixbuf_get_n_channels gdk_pixbuf_get_n_channels +#define fn_gdk_pixbuf_get_has_alpha gdk_pixbuf_get_has_alpha +#define fn_gdk_pixbuf_get_bits_per_sample gdk_pixbuf_get_bits_per_sample + + +/* Load SVG image IMG for use on frame F. Value is non-zero if + successful. this function will go into the svg_type structure, and + the prototype thus needs to be compatible with that structure. */ + +static int +svg_load (f, img) + struct frame *f; + struct image *img; +{ + int success_p = 0; + Lisp_Object file_name; + + /* If IMG->spec specifies a file name, create a non-file spec from it. */ + file_name = image_spec_value (img->spec, QCfile, NULL); + if (STRINGP (file_name)) + { + Lisp_Object file; + unsigned char *contents; + int size; + struct gcpro gcpro1; + + file = x_find_image_file (file_name); + GCPRO1 (file); + if (!STRINGP (file)) + { + image_error ("Cannot find image file `%s'", file_name, Qnil); + UNGCPRO; + return 0; + } + + /* Read the entire file into memory. */ + contents = slurp_file (SDATA (file), &size); + if (contents == NULL) + { + image_error ("Error loading SVG image `%s'", img->spec, Qnil); + UNGCPRO; + return 0; + } + /* If the file was slurped into memory properly, parse it. */ + success_p = svg_load_image (f, img, contents, size); + xfree (contents); + UNGCPRO; + } + /* Else its not a file, its a lisp object. Load the image from a + lisp object rather than a file. */ + else + { + Lisp_Object data; + + data = image_spec_value (img->spec, QCdata, NULL); + success_p = svg_load_image (f, img, SDATA (data), SBYTES (data)); + } + + return success_p; +} + +/* svg_load_image is a helper function for svg_load, which does the actual + loading given contents and size, apart from frame and image + structures, passed from svg_load. + + Uses librsvg to do most of the image processing. + + Returns non-zero when sucessful. */ +static int +svg_load_image (f, img, contents, size) + /* Pointer to emacs frame sturcture. */ + struct frame *f; + /* Pointer to emacs image structure. */ + struct image *img; + /* String containing the SVG XML data to be parsed. */ + unsigned char *contents; + /* Size of data in bytes. */ + unsigned int size; +{ + RsvgHandle *rsvg_handle; + GError *error = NULL; + GdkPixbuf *pixbuf; + int width; + int height; + const guint8 *pixels; + int rowstride; + XImagePtr ximg; + XColor background; + int x; + int y; + + /* g_type_init is a glib function that must be called prior to using + gnome type library functions. */ + g_type_init (); + /* Make a handle to a new rsvg object. */ + rsvg_handle = fn_rsvg_handle_new (); + + /* Parse the contents argument and fill in the rsvg_handle. */ + fn_rsvg_handle_write (rsvg_handle, contents, size, &error); + if (error) + goto rsvg_error; + + /* The parsing is complete, rsvg_handle is ready to used, close it + for further writes. */ + fn_rsvg_handle_close (rsvg_handle, &error); + if (error) + goto rsvg_error; + /* We can now get a valid pixel buffer from the svg file, if all + went ok. */ + pixbuf = fn_rsvg_handle_get_pixbuf (rsvg_handle); + eassert (pixbuf); + + /* Extract some meta data from the svg handle. */ + width = fn_gdk_pixbuf_get_width (pixbuf); + height = fn_gdk_pixbuf_get_height (pixbuf); + pixels = fn_gdk_pixbuf_get_pixels (pixbuf); + rowstride = fn_gdk_pixbuf_get_rowstride (pixbuf); + + /* Validate the svg meta data. */ + eassert (fn_gdk_pixbuf_get_colorspace (pixbuf) == GDK_COLORSPACE_RGB); + eassert (fn_gdk_pixbuf_get_n_channels (pixbuf) == 4); + eassert (fn_gdk_pixbuf_get_has_alpha (pixbuf)); + eassert (fn_gdk_pixbuf_get_bits_per_sample (pixbuf) == 8); + + /* Try to create a x pixmap to hold the svg pixmap. */ + if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap)) { + g_object_unref (pixbuf); + return 0; + } + + init_color_table (); + + /* TODO: The code is somewhat prepared for other environments than + X, but is far from done. */ +#ifdef HAVE_X_WINDOWS + + background.pixel = FRAME_BACKGROUND_PIXEL (f); + x_query_color (f, &background); + + /* SVG pixmaps specify transparency in the last byte, so right shift + 8 bits to get rid of it, since emacs doesnt support + transparency. */ + background.red >>= 8; + background.green >>= 8; + background.blue >>= 8; + +#else /* not HAVE_X_WINDOWS */ +#error FIXME +#endif + + /* This loop handles opacity values, since Emacs assumes + non-transparent images. Each pixel must be "flattened" by + calculating he resulting color, given the transparency of the + pixel, and the image background color. */ + for (y = 0; y < height; ++y) + { + for (x = 0; x < width; ++x) + { + unsigned red; + unsigned green; + unsigned blue; + unsigned opacity; + + red = *pixels++; + green = *pixels++; + blue = *pixels++; + opacity = *pixels++; + + red = ((red * opacity) + + (background.red * ((1 << 8) - opacity))); + green = ((green * opacity) + + (background.green * ((1 << 8) - opacity))); + blue = ((blue * opacity) + + (background.blue * ((1 << 8) - opacity))); + + XPutPixel (ximg, x, y, lookup_rgb_color (f, red, green, blue)); + } + + pixels += rowstride - 4 * width; + } + +#ifdef COLOR_TABLE_SUPPORT + /* Remember colors allocated for this image. */ + img->colors = colors_in_color_table (&img->ncolors); + free_color_table (); +#endif /* COLOR_TABLE_SUPPORT */ + + g_object_unref (pixbuf); + + /* Put the image into the pixmap, then free the X image and its + buffer. */ + x_put_x_image (f, ximg, img->pixmap, width, height); + x_destroy_x_image (ximg); + + img->width = width; + img->height = height; + + return 1; + + rsvg_error: + /* FIXME: Use error->message so the user knows what is the actual + problem with the image. */ + image_error ("Error parsing SVG image `%s'", img->spec, Qnil); + g_error_free (error); + return 0; +} + +#endif /* defined (HAVE_RSVG) */ + + + /*********************************************************************** Ghostscript @@ -8591,6 +8914,11 @@ of `image-library-alist', which see). * return CHECK_LIB_AVAILABLE (&png_type, init_png_functions, libraries); #endif +#if defined (HAVE_RSVG) + if (EQ (type, Qsvg)) + return CHECK_LIB_AVAILABLE (&svg_type, init_svg_functions, libraries); +#endif + #ifdef HAVE_GHOSTSCRIPT if (EQ (type, Qpostscript)) return CHECK_LIB_AVAILABLE (&gs_type, init_gs_functions, libraries); @@ -8733,6 +9061,13 @@ non-numeric, there is no explicit limit ADD_IMAGE_TYPE(Qpng); #endif +#if defined (HAVE_RSVG) + Qsvg = intern ("svg"); + staticpro (&Qsvg); + ADD_IMAGE_TYPE(Qsvg); +#endif + + defsubr (&Sinit_image_library); defsubr (&Sclear_image_cache); defsubr (&Simage_refresh);