From mboxrd@z Thu Jan 1 00:00:00 1970 Path: main.gmane.org!not-for-mail From: Paul Pogonyshev Newsgroups: gmane.emacs.devel Subject: Re: SVG and Emacs Date: Sat, 25 Sep 2004 18:31:08 -0200 Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Message-ID: <200409251830.09538.pogonyshev@gmx.net> References: <200409192302.00885.pogonyshev@gmx.net> <200409201838.06056.pogonyshev@gmx.net> NNTP-Posting-Host: deer.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-Trace: sea.gmane.org 1096126188 6877 80.91.229.6 (25 Sep 2004 15:29:48 GMT) X-Complaints-To: usenet@sea.gmane.org NNTP-Posting-Date: Sat, 25 Sep 2004 15:29:48 +0000 (UTC) Cc: emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Sat Sep 25 17:29:34 2004 Return-path: Original-Received: from lists.gnu.org ([199.232.76.165]) by deer.gmane.org with esmtp (Exim 3.35 #1 (Debian)) id 1CBEUP-0007us-00 for ; Sat, 25 Sep 2004 17:29:33 +0200 Original-Received: from localhost ([127.0.0.1] helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.33) id 1CBEaW-0006pz-4I for ged-emacs-devel@m.gmane.org; Sat, 25 Sep 2004 11:35:52 -0400 Original-Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.33) id 1CBEaP-0006pt-2L for emacs-devel@gnu.org; Sat, 25 Sep 2004 11:35:45 -0400 Original-Received: from exim by lists.gnu.org with spam-scanned (Exim 4.33) id 1CBEaN-0006oD-JX for emacs-devel@gnu.org; Sat, 25 Sep 2004 11:35:44 -0400 Original-Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.33) id 1CBEaN-0006oA-Ge for emacs-devel@gnu.org; Sat, 25 Sep 2004 11:35:43 -0400 Original-Received: from [213.165.64.20] (helo=mail.gmx.net) by monty-python.gnu.org with smtp (Exim 4.34) id 1CBETj-0003Mg-3w for emacs-devel@gnu.org; Sat, 25 Sep 2004 11:28:51 -0400 Original-Received: (qmail 23040 invoked by uid 65534); 25 Sep 2004 15:28:44 -0000 Original-Received: from unknown (EHLO localhost.localdomain) (195.50.12.115) by mail.gmx.net (mp001) with SMTP; 25 Sep 2004 17:28:44 +0200 X-Authenticated: #16844820 Original-To: rms@gnu.org User-Agent: KMail/1.4.3 In-Reply-To: X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: main.gmane.org gmane.emacs.devel:27559 X-Report-Spam: http://spam.gmane.org/gmane.emacs.devel:27559 RMS wrote: > Actually, librsvg doesn't use full GTK+, only gdk-pixbuf, > GLib and Pango. Maybe it could be made dynamically-loadable > (though I can't say I'm familiar with dynamic library loading). > > Maybe that is ok. Here is the first shot. It is extremely non-portable, hackish and ugly, but it works! :) Do we want to continue in this direction? If yes, then I'm open for suggestions, especially on how to improve `configure.in' and `Makefile.in' bits. Portability is also a major issue. I only work under GNU/Linux and I don't really know how portable `librsvg' is, in the first place. Also, do we want to make SVG rendering dynamically loadable (optionally?) Actually, if we go on this, we can as well make all the rest of image renderers load their libraries with dlopen(). =46rom what I understood by looking at the code, the libraries are already loaded dynamically under WinNT, so there must not be any principal show-stoppers here. Note that many ``1 ||'' in `image.c' are because I didn't run Autoheader and so `HAVE_RSVG' didn't make its way to `config.h'. Two side note on `configure.in': * Many modules (i.e. image-rendering modules) that are built by default are mentioned as `--with-xxx use -lxxx ...' in the help output. It seems more logical to write `--without-xxx don't use -lxxx ...' * Maybe it is better to use AC_HELP_STRING()? Paul --- configure.in=0904 May 2004 19:24:09 -0200=091.367 +++ configure.in=0925 Sep 2004 16:16:10 -0200=09 @@ -109,10 +109,12 @@ AC_ARG_WITH(gif, [ --with-gif use -lungif for displaying GIF images]) AC_ARG_WITH(png, [ --with-png use -lpng for displaying PNG images]) +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=3Dgtk)]) 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]) @@ -1926,6 +1928,31 @@ AC_DEFUN([PKG_CHECK_MODULES], [ fi ]) =20 +### Use -lrsvg-2 if available, unless `--with-rsvg=3Dno' is specified. +HAVE_RSVG=3Dno +if test "${HAVE_X11}" =3D "yes"; then + if test "${with_rsvg}" !=3D "no"; then + dnl Check if `--with-pkg-config-prog' has been given. + if test "X${with_pkg_config_prog}" !=3D X; then + PKG_CONFIG=3D"${with_pkg_config_prog}" + fi + + RSVG_REQUIRED=3D2.0.0 + RSVG_MODULE=3D"librsvg-2.0 >=3D $RSVG_REQUIRED" + + PKG_CHECK_MODULES(RSVG, $RSVG_MODULE, :, :) + AC_SUBST(RSVG_CFLAGS) + AC_SUBST(RSVG_LIBS) + + if test ".${RSVG_CFLAGS}" !=3D "."; then + HAVE_RSVG=3Dyes + AC_DEFINE(HAVE_RSVG, 1, [Define to 1 if using librsvg.]) + CFLAGS=3D"$CFLAGS $RSVG_CFLAGS" + LIBS=3D"$RSVG_LIBS $LIBS" + fi + fi +fi + HAVE_GTK=3Dno if test "${with_gtk}" =3D "yes" || test "$USE_X_TOOLKIT" =3D "gtk"; then if test "$USE_X_TOOLKIT" !=3D "none" && test "$USE_X_TOOLKIT" !=3D "ma= ybe"; then @@ -3035,6 +3062,7 @@ echo " Does Emacs use -ljpeg? =20 echo " Does Emacs use -ltiff? ${HAVE_T= IFF}" echo " Does Emacs use -lungif? ${HAVE_G= IF}" echo " Does Emacs use -lpng? ${HAVE_P= NG}" +echo " Does Emacs use -lrsvg-2? ${HAVE_R= SVG}" echo " Does Emacs use X toolkit scroll bars? ${USE_TO= OLKIT_SCROLL_BARS}" echo =20 --- lisp/image-file.el=0901 Sep 2003 13:45:13 -0200=091.19 +++ lisp/image-file.el=0925 Sep 2004 17:54:33 -0200=09 @@ -38,7 +38,7 @@ =20 ;;;###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'. --- lisp/image.el=0921 Jun 2004 19:52:28 -0200=091.42 +++ lisp/image.el=0925 Sep 2004 17:58:38 -0200=09 @@ -40,7 +40,8 @@ ("\\`[\t\n\r ]*#define" . 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, --- src/image.c=0930 Jun 2004 11:11:36 -0200=091.16 +++ src/image.c=0925 Sep 2004 18:16:31 -0200=09 @@ -7589,6 +7589,277 @@ gif_load (f, img) =20 #endif /* HAVE_GIF */ =20 +=20 +/*********************************************************************** +=09=09=09=09 SVG + ***********************************************************************= / + +#if 1 || 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 *, +=09=09=09 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] =3D +{ + {":type",=09=09IMAGE_SYMBOL_VALUE,=09=09=091}, + {":data",=09=09IMAGE_STRING_VALUE,=09=09=090}, + {":file",=09=09IMAGE_STRING_VALUE,=09=09=090}, + {":ascent",=09=09IMAGE_ASCENT_VALUE,=09=09=090}, + {":margin",=09=09IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,=090}, + {":relief",=09=09IMAGE_INTEGER_VALUE,=09=09=090}, + {":conversion",=09IMAGE_DONT_CHECK_VALUE_TYPE,=09=090}, + {":heuristic-mask",=09IMAGE_DONT_CHECK_VALUE_TYPE,=09=090}, + {":mask",=09=09IMAGE_DONT_CHECK_VALUE_TYPE,=09=090}, + {":background",=09IMAGE_STRING_OR_NIL_VALUE,=09=090} +}; + +/* Structure describing the image type `svg'. */ + +static struct image_type svg_type =3D +{ + &Qsvg, + svg_image_p, + svg_load, + x_clear_image, + NULL +}; + + +/* Return non-zero if OBJECT is a valid SVG image specification. */ + +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 =3D=3D 1; +} + +#include + +/* DEF_IMGLIB_FN() here? */ + +#define fn_rsvg_handle_new=09=09rsvg_handle_new +#define fn_rsvg_handle_set_size_callback rsvg_handle_set_size_callback +#define fn_rsvg_handle_write=09=09rsvg_handle_write +#define fn_rsvg_handle_close=09=09rsvg_handle_close +#define fn_rsvg_handle_get_pixbuf=09rsvg_handle_get_pixbuf +#define fn_rsvg_handle_free=09=09rsvg_handle_free + +#define fn_gdk_pixbuf_get_width=09=09gdk_pixbuf_get_width +#define fn_gdk_pixbuf_get_height=09gdk_pixbuf_get_height +#define fn_gdk_pixbuf_get_pixels=09gdk_pixbuf_get_pixels +#define fn_gdk_pixbuf_get_rowstride=09gdk_pixbuf_get_rowstride +#define fn_gdk_pixbuf_get_colorspace=09gdk_pixbuf_get_colorspace +#define fn_gdk_pixbuf_get_n_channels=09gdk_pixbuf_get_n_channels +#define fn_gdk_pixbuf_get_has_alpha=09gdk_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. */ + +static int +svg_load (f, img) + struct frame *f; + struct image *img; +{ + int success_p =3D 0; + Lisp_Object file_name; + + /* If IMG->spec specifies a file name, create a non-file spec from it.= */ + file_name =3D image_spec_value (img->spec, QCfile, NULL); + if (STRINGP (file_name)) + { + Lisp_Object file; + unsigned char *contents; + int size; + struct gcpro gcpro1; + + file =3D x_find_image_file (file_name); + GCPRO1 (file); + if (!STRINGP (file)) + { + image_error ("Cannot find image file `%s'", file_name, Qnil); + UNGCPRO; + return 0; + } + + contents =3D slurp_file (SDATA (file), &size); + if (contents =3D=3D NULL) + { + image_error ("Error loading SVG image `%s'", img->spec, Qnil); + UNGCPRO; + return 0; + } + + success_p =3D svg_load_image (f, img, contents, size); + xfree (contents); + UNGCPRO; + } + else + { + Lisp_Object data; + + data =3D image_spec_value (img->spec, QCdata, NULL); + success_p =3D svg_load_image (f, img, SDATA (data), SBYTES (data))= ; + } + + return success_p; +} + + +static int +svg_load_image (f, img, contents, size) + struct frame *f; + struct image *img; + unsigned char *contents; + unsigned int size; +{ + RsvgHandle *rsvg_handle; + GError *error =3D NULL; + GdkPixbuf *pixbuf; + int width; + int height; + const guint8 *pixels; + int rowstride; + XImagePtr ximg; + XColor background; + int x; + int y; + + g_type_init (); + rsvg_handle =3D fn_rsvg_handle_new (); + + fn_rsvg_handle_write (rsvg_handle, contents, size, &error); + if (error) + goto rsvg_error; + + fn_rsvg_handle_close (rsvg_handle, &error); + if (error) + goto rsvg_error; + + pixbuf =3D fn_rsvg_handle_get_pixbuf (rsvg_handle); + eassert (pixbuf); + + width =3D fn_gdk_pixbuf_get_width (pixbuf); + height =3D fn_gdk_pixbuf_get_height (pixbuf); + pixels =3D fn_gdk_pixbuf_get_pixels (pixbuf); + rowstride =3D fn_gdk_pixbuf_get_rowstride (pixbuf); + + eassert (fn_gdk_pixbuf_get_colorspace (pixbuf) =3D=3D GDK_COLORSPACE_R= GB); + eassert (fn_gdk_pixbuf_get_n_channels (pixbuf) =3D=3D 4); + eassert (fn_gdk_pixbuf_get_has_alpha (pixbuf)); + eassert (fn_gdk_pixbuf_get_bits_per_sample (pixbuf) =3D=3D 8); + + if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pi= xmap)) { + g_object_unref (pixbuf); + return 0; + } + + init_color_table (); + +#ifdef HAVE_X_WINDOWS + + background.pixel =3D FRAME_BACKGROUND_PIXEL (f); + x_query_color (f, &background); + + background.red >>=3D 8; + background.green >>=3D 8; + background.blue >>=3D 8; + +#else /* not HAVE_X_WINDOWS */ +#error FIXME +#endif + + for (y =3D 0; y < height; ++y) + { + for (x =3D 0; x < width; ++x) +=09{ +=09 unsigned red; +=09 unsigned green; +=09 unsigned blue; +=09 unsigned opacity; + +=09 red =3D *pixels++; +=09 green =3D *pixels++; +=09 blue =3D *pixels++; +=09 opacity =3D *pixels++; + +=09 red =3D ((red * opacity) +=09=09 + (background.red * ((1 << 8) - opacity))); +=09 green =3D ((green * opacity) +=09=09 + (background.green * ((1 << 8) - opacity))); +=09 blue =3D ((blue * opacity) +=09=09 + (background.blue * ((1 << 8) - opacity))); + +=09 XPutPixel (ximg, x, y, lookup_rgb_color (f, red, green, blue)); +=09} + + pixels +=3D rowstride - 4 * width; + } + +#ifdef COLOR_TABLE_SUPPORT + /* Remember colors allocated for this image. */ + img->colors =3D 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= =2E */ + x_put_x_image (f, ximg, img->pixmap, width, height); + x_destroy_x_image (ximg); + + img->width =3D width; + img->height =3D height; + + return 1; + + rsvg_error: + /* FIXME: Use error->message. */ + image_error ("Error parsing SVG image `%s'", img->spec, Qnil); + g_error_free (error); + return 0; +} + +#endif=09/* defined (HAVE_RSVG) */ + =20 =20 /*********************************************************************** @@ -7976,6 +8247,11 @@ of `image-library-alist', which see). * return CHECK_LIB_AVAILABLE (&png_type, init_png_functions, libraries= ); #endif =20 +#if 1 || 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); @@ -8082,6 +8358,12 @@ To check whether it is really supported, ADD_IMAGE_TYPE(Qpng); #endif =20 +#if 1 || defined (HAVE_RSVG) + Qsvg =3D intern ("svg"); + staticpro (&Qsvg); + ADD_IMAGE_TYPE(Qsvg); +#endif + defsubr (&Sinit_image_library); defsubr (&Sclear_image_cache); defsubr (&Simage_size); --- src/Makefile.in=0910 Sep 2004 21:26:00 -0200=091.300 +++ src/Makefile.in=0925 Sep 2004 16:25:50 -0200=09 @@ -280,7 +280,7 @@ TOOLKIT_DEFINES =3D =20 /* C_SWITCH_X_SITE must come before C_SWITCH_X_MACHINE and C_SWITCH_X_SY= STEM since it may have -I options that should override those two. */ -ALL_CFLAGS=3D-Demacs -DHAVE_CONFIG_H $(TOOLKIT_DEFINES) $(MYCPPFLAGS) -I= =2E -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 ${CFLAG= S} +ALL_CFLAGS=3D-Demacs -DHAVE_CONFIG_H $(TOOLKIT_DEFINES) $(MYCPPFLAGS) -I= =2E -I${srcdir} C_SWITCH_MACHINE C_SWITCH_SYSTEM C_SWITCH_SITE @RSVG_CFLA= GS@ C_SWITCH_X_SITE C_SWITCH_X_MACHINE C_SWITCH_X_SYSTEM C_SWITCH_SYSTEM_= TEMACS ${CFLAGS} .c.o: =09$(CC) -c $(CPPFLAGS) $(ALL_CFLAGS) $< =20 @@ -444,7 +444,7 @@ LIBXT=3D$(LIBW) /* LD_SWITCH_X_DEFAULT comes after everything else that specifies options for where to find X libraries, but before those libraries. *= / X11_LDFLAGS =3D LD_SWITCH_X_SITE LD_SWITCH_X_DEFAULT -LIBX=3D $(LIBXMENU) $(X11_LDFLAGS) $(LIBXT) LIBTIFF LIBJPEG LIBPNG LIBGI= F LIBXPM LIB_X11_LIB LIBX11_MACHINE LIBX11_SYSTEM +LIBX=3D $(LIBXMENU) $(X11_LDFLAGS) $(LIBXT) LIBTIFF LIBJPEG LIBPNG LIBGI= F LIBXPM @RSVG_LIBS@ LIB_X11_LIB LIBX11_MACHINE LIBX11_SYSTEM #else /* not HAVE_X11 */ LIBX=3D $(LIBXMENU) LD_SWITCH_X_SITE -lX10 LIBX10_MACHINE LIBX10_SYSTEM #endif /* not HAVE_X11 */