unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: Alan Third <alan@idiocy.org>
To: Eli Zaretskii <eliz@gnu.org>
Cc: stefan@marxist.se, 47074@debbugs.gnu.org
Subject: bug#47074: Replace XPM icons with Unicode codepoints in customize/widgets
Date: Mon, 15 Mar 2021 21:34:24 +0000	[thread overview]
Message-ID: <YE/S4DJlJMvGMCG+@breton.holly.idiocy.org> (raw)
In-Reply-To: <83im5tfr6t.fsf@gnu.org>

[-- Attachment #1: Type: text/plain, Size: 771 bytes --]

On Sun, Mar 14, 2021 at 09:52:58PM +0200, Eli Zaretskii wrote:
> > Date: Sun, 14 Mar 2021 19:37:33 +0000
> > From: Alan Third <alan@idiocy.org>
> > Cc: Stefan Kangas <stefan@marxist.se>, 47074@debbugs.gnu.org
> > 
> > > The only question I have is what will happen if librsvg is older than
> > > 2.48?
> > 
> > It will work exactly as it works at the moment. The font size will be
> > set to the librsvg default, which I think is 16 pixels, so the images
> > will default to 16 pixels high.
> 
> Then that's fine, I think.  Thanks for doing this.

Here's my final patch, then. Again Stefan's patch is required first.

I'm somewhat tempted to add a :css image attribute for SVG files to
allow the user to over-ride the default css, but I can do that later.
-- 
Alan Third

[-- Attachment #2: 0001-Set-CSS-for-SVG-files.patch --]
[-- Type: text/plain, Size: 12954 bytes --]

From 50d2b5968f25ff0c1915db324669f56ff035416c Mon Sep 17 00:00:00 2001
From: Alan Third <alan@idiocy.org>
Date: Mon, 15 Mar 2021 21:30:43 +0000
Subject: [PATCH] Set CSS for SVG files

* etc/images/ui/checkbox-checked.svg:
* etc/images/ui/checkbox-mixed.svg:
* etc/images/ui/checkbox.svg:
* etc/images/ui/radio-checked.svg:
* etc/images/ui/radio-mixed.svg:
* etc/images/ui/radio.svg: Set height to match the font size.
* src/dispextern.h (struct image): Add font details required for the CSS.
* src/image.c (free_image): Free the font family string.
(search_image_cache):
(uncache_image): Make image caching understand the font details.
(lookup_image): Handle the font details when generating the image and
looking up the cache.
(svg_css_length_to_pixels): Handle 'em' when we know the font size.
(svg_load_image): Generate the CSS and apply it to the SVG.
---
 etc/images/ui/checkbox-checked.svg |  2 +-
 etc/images/ui/checkbox-mixed.svg   |  2 +-
 etc/images/ui/checkbox.svg         |  2 +-
 etc/images/ui/radio-checked.svg    |  2 +-
 etc/images/ui/radio-mixed.svg      |  2 +-
 etc/images/ui/radio.svg            |  2 +-
 src/dispextern.h                   |  5 +++
 src/image.c                        | 64 +++++++++++++++++++++++-------
 8 files changed, 60 insertions(+), 21 deletions(-)

diff --git a/etc/images/ui/checkbox-checked.svg b/etc/images/ui/checkbox-checked.svg
index 6fefd5569e..b84dde1c3a 100644
--- a/etc/images/ui/checkbox-checked.svg
+++ b/etc/images/ui/checkbox-checked.svg
@@ -1,4 +1,4 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16">
+<svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 16 16">
   <g>
     <path d="M3.5 1A2.506 2.506 0 001 3.5v9C1 13.876 2.124 15 3.5 15h9c1.376 0 2.5-1.124 2.5-2.5v-9C15 2.124 13.876 1 12.5 1zm0 1h9c.84 0 1.5.66 1.5 1.5v9c0 .84-.66 1.5-1.5 1.5h-9c-.84 0-1.5-.66-1.5-1.5v-9C2 2.66 2.66 2 3.5 2z" overflow="visible" />
     <path d="M14.5 3l-.5-.5L7.5 9 5 6.5l-2 2L7.5 13l7-7z" overflow="visible" />
diff --git a/etc/images/ui/checkbox-mixed.svg b/etc/images/ui/checkbox-mixed.svg
index 13bccaa7ce..647a0ccf9b 100644
--- a/etc/images/ui/checkbox-mixed.svg
+++ b/etc/images/ui/checkbox-mixed.svg
@@ -1,4 +1,4 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16">
+<svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 16 16">
   <g>
     <path d="M3.5 1A2.506 2.506 0 001 3.5v9C1 13.876 2.124 15 3.5 15h9c1.376 0 2.5-1.124 2.5-2.5v-9C15 2.124 13.876 1 12.5 1zm0 1h9c.84 0 1.5.66 1.5 1.5v9c0 .84-.66 1.5-1.5 1.5h-9c-.84 0-1.5-.66-1.5-1.5v-9C2 2.66 2.66 2 3.5 2z" overflow="visible" />
     <path d="M5 6a2 2 0 100 4h6a2 2 0 100-4z" overflow="visible" />
diff --git a/etc/images/ui/checkbox.svg b/etc/images/ui/checkbox.svg
index 18cd25b43f..7cc1516220 100644
--- a/etc/images/ui/checkbox.svg
+++ b/etc/images/ui/checkbox.svg
@@ -1,3 +1,3 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16">
+<svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 16 16">
   <path d="M3.5 1A2.506 2.506 0 001 3.5v9C1 13.876 2.124 15 3.5 15h9c1.376 0 2.5-1.124 2.5-2.5v-9C15 2.124 13.876 1 12.5 1zm0 1h9c.84 0 1.5.66 1.5 1.5v9c0 .84-.66 1.5-1.5 1.5h-9c-.84 0-1.5-.66-1.5-1.5v-9C2 2.66 2.66 2 3.5 2z" overflow="visible" />
 </svg>
diff --git a/etc/images/ui/radio-checked.svg b/etc/images/ui/radio-checked.svg
index db711841cf..5354324c34 100644
--- a/etc/images/ui/radio-checked.svg
+++ b/etc/images/ui/radio-checked.svg
@@ -1,4 +1,4 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16">
+<svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 16 16">
   <g>
     <path d="M8 5a3.001 3.001 0 000 6 3.001 3.001 0 000-6z" overflow="visible"/>
     <path d="M8.004 1C4.144 1 1 4.144 1 8.004c0 3.86 3.144 7.006 7.004 7.006 3.86 0 7.006-3.146 7.006-7.006C15.01 4.144 11.864 1 8.004 1zm0 1a6.002 6.002 0 016.006 6.004 6.004 6.004 0 01-6.006 6.006A6.002 6.002 0 012 8.004 6 6 0 018.004 2z" overflow="visible"/>
diff --git a/etc/images/ui/radio-mixed.svg b/etc/images/ui/radio-mixed.svg
index 5a8be0cf65..e2a6fcae57 100644
--- a/etc/images/ui/radio-mixed.svg
+++ b/etc/images/ui/radio-mixed.svg
@@ -1,4 +1,4 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16">
+<svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 16 16">
   <g font-weight="400" fill="#474747">
     <path d="M8 1C4.142 1 1 4.142 1 8s3.142 7 7 7 7-3.142 7-7-3.142-7-7-7zm0 1c3.316 0 6 2.684 6 6s-2.684 6-6 6-6-2.684-6-6 2.684-6 6-6z" overflow="visible" />
     <path d="M5 6a2 2 0 100 4h6a2 2 0 100-4z" overflow="visible" />
diff --git a/etc/images/ui/radio.svg b/etc/images/ui/radio.svg
index 0d649c99cd..2593a78610 100644
--- a/etc/images/ui/radio.svg
+++ b/etc/images/ui/radio.svg
@@ -1,3 +1,3 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16">
+<svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 16 16">
   <path d="M8 1C4.142 1 1 4.142 1 8s3.142 7 7 7 7-3.142 7-7-3.142-7-7-7zm0 1c3.316 0 6 2.684 6 6s-2.684 6-6 6-6-2.684-6-6 2.684-6 6-6z" overflow="visible" />
 </svg>
diff --git a/src/dispextern.h b/src/dispextern.h
index f4e872644d..a2ebd04f23 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -3066,6 +3066,11 @@ reset_mouse_highlight (Mouse_HLInfo *hlinfo)
      is created.  */
   unsigned long face_foreground, face_background;
 
+  /* Details of the font, only really relevant for types like SVG that
+     allow us to draw text. */
+  int face_font_size;
+  char *face_font_family;
+
   /* True if this image has a `transparent' background -- that is, is
      uses an image mask.  The accessor macro for this is
      `IMAGE_BACKGROUND_TRANSPARENT'.  */
diff --git a/src/image.c b/src/image.c
index b85418c690..3d504effa6 100644
--- a/src/image.c
+++ b/src/image.c
@@ -1207,6 +1207,7 @@ free_image (struct frame *f, struct image *img)
 
       /* Free resources, then free IMG.  */
       img->type->free_img (f, img);
+      xfree (img->face_font_family);
       xfree (img);
     }
 }
@@ -1605,7 +1606,7 @@ make_image_cache (void)
 static struct image *
 search_image_cache (struct frame *f, Lisp_Object spec, EMACS_UINT hash,
                     unsigned long foreground, unsigned long background,
-                    bool ignore_colors)
+                    int font_size, char *font_family, bool ignore_colors)
 {
   struct image *img;
   struct image_cache *c = FRAME_IMAGE_CACHE (f);
@@ -1629,7 +1630,10 @@ search_image_cache (struct frame *f, Lisp_Object spec, EMACS_UINT hash,
     if (img->hash == hash
 	&& !NILP (Fequal (img->spec, spec))
 	&& (ignore_colors || (img->face_foreground == foreground
-                              && img->face_background == background)))
+                              && img->face_background == background
+			      && img->face_font_size == font_size
+			      && (font_family
+				  &&!strcmp (font_family, img->face_font_family)))))
       break;
   return img;
 }
@@ -1647,7 +1651,7 @@ uncache_image (struct frame *f, Lisp_Object spec)
      can have multiple copies of an image with the same spec. We want
      to remove them all to ensure the user doesn't see an old version
      of the image when the face changes.  */
-  while ((img = search_image_cache (f, spec, hash, 0, 0, true)))
+  while ((img = search_image_cache (f, spec, hash, 0, 0, 0, NULL, true)))
     {
       free_image (f, img);
       /* As display glyphs may still be referring to the image ID, we
@@ -2419,6 +2423,8 @@ lookup_image (struct frame *f, Lisp_Object spec, int face_id)
   struct face *face = FACE_FROM_ID (f, face_id);
   unsigned long foreground = FACE_COLOR_TO_PIXEL (face->foreground, f);
   unsigned long background = FACE_COLOR_TO_PIXEL (face->background, f);
+  int font_size = face->font->pixel_size;
+  char *font_family = SSDATA (face->lface[LFACE_FAMILY_INDEX]);
 
   /* F must be a window-system frame, and SPEC must be a valid image
      specification.  */
@@ -2427,7 +2433,8 @@ lookup_image (struct frame *f, Lisp_Object spec, int face_id)
 
   /* Look up SPEC in the hash table of the image cache.  */
   hash = sxhash (spec);
-  img = search_image_cache (f, spec, hash, foreground, background, false);
+  img = search_image_cache (f, spec, hash, foreground, background,
+			    font_size, font_family, false);
   if (img && img->load_failed_p)
     {
       free_image (f, img);
@@ -2442,6 +2449,9 @@ lookup_image (struct frame *f, Lisp_Object spec, int face_id)
       cache_image (f, img);
       img->face_foreground = foreground;
       img->face_background = background;
+      img->face_font_size = font_size;
+      img->face_font_family = malloc (strlen (font_family) + 1);
+      strcpy (img->face_font_family, font_family);
       img->load_failed_p = ! img->type->load_img (f, img);
 
       /* If we can't load the image, and we don't have a width and
@@ -9846,7 +9856,7 @@ svg_load (struct frame *f, struct image *img)
 
 #if LIBRSVG_CHECK_VERSION (2, 46, 0)
 static double
-svg_css_length_to_pixels (RsvgLength length, double dpi)
+svg_css_length_to_pixels (RsvgLength length, double dpi, int font_size)
 {
   double value = length.length;
 
@@ -9874,9 +9884,16 @@ svg_css_length_to_pixels (RsvgLength length, double dpi)
     case RSVG_UNIT_IN:
       value *= dpi;
       break;
+#if LIBRSVG_CHECK_VERSION (2, 48, 0)
+      /* We don't know exactly what font size is used on older librsvg
+	 versions.  */
+    case RSVG_UNIT_EM:
+      value *= font_size;
+      break;
+#endif
     default:
-      /* Probably one of em, ex, or %.  We can't know what the pixel
-         value is without more information.  */
+      /* Probably ex or %.  We can't know what the pixel value is
+         without more information.  */
       value = 0;
     }
 
@@ -9931,6 +9948,16 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
 
   rsvg_handle_set_dpi_x_y (rsvg_handle, FRAME_DISPLAY_INFO (f)->resx,
                            FRAME_DISPLAY_INFO (f)->resy);
+
+#if LIBRSVG_CHECK_VERSION (2, 48, 0)
+  /* Generate the CSS for the SVG image.  */
+  char *css_spec = "svg{font-family:\"%s\";font-size:%4dpx}";
+  int css_len = strlen (css_spec) + strlen (img->face_font_family);
+  char *css = xmalloc(css_len);
+  snprintf (css, css_len, css_spec, img->face_font_family, img->face_font_size);
+  rsvg_handle_set_stylesheet (rsvg_handle, css, strlen (css), NULL);
+#endif
+
 #else
   /* Make a handle to a new rsvg object.  */
   rsvg_handle = rsvg_handle_new ();
@@ -9973,20 +10000,20 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
   if (has_width && has_height)
     {
       /* Success!  We can use these values directly.  */
-      viewbox_width = svg_css_length_to_pixels (iwidth, dpi);
-      viewbox_height = svg_css_length_to_pixels (iheight, dpi);
+      viewbox_width = svg_css_length_to_pixels (iwidth, dpi, img->face_font_size);
+      viewbox_height = svg_css_length_to_pixels (iheight, dpi, img->face_font_size);
     }
   else if (has_width && has_viewbox)
     {
-      viewbox_width = svg_css_length_to_pixels (iwidth, dpi);
-      viewbox_height = svg_css_length_to_pixels (iwidth, dpi)
-        * viewbox.width / viewbox.height;
+      viewbox_width = svg_css_length_to_pixels (iwidth, dpi, img->face_font_size);
+      viewbox_height = svg_css_length_to_pixels (iwidth, dpi, img->face_font_size)
+        * viewbox.height / viewbox.width;
     }
   else if (has_height && has_viewbox)
     {
-      viewbox_height = svg_css_length_to_pixels (iheight, dpi);
-      viewbox_width = svg_css_length_to_pixels (iheight, dpi)
-        * viewbox.height / viewbox.width;
+      viewbox_height = svg_css_length_to_pixels (iheight, dpi, img->face_font_size);
+      viewbox_width = svg_css_length_to_pixels (iheight, dpi, img->face_font_size)
+        * viewbox.width / viewbox.height;
     }
   else if (has_viewbox)
     {
@@ -10107,6 +10134,10 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
 
   rsvg_handle_set_dpi_x_y (rsvg_handle, FRAME_DISPLAY_INFO (f)->resx,
                            FRAME_DISPLAY_INFO (f)->resy);
+
+#if LIBRSVG_CHECK_VERSION (2, 48, 0)
+  rsvg_handle_set_stylesheet (rsvg_handle, css, strlen (css), NULL);
+#endif
 #else
   /* Make a handle to a new rsvg object.  */
   rsvg_handle = rsvg_handle_new ();
@@ -10139,6 +10170,7 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
   if (!pixbuf) goto rsvg_error;
   g_object_unref (rsvg_handle);
   xfree (wrapped_contents);
+  xfree (css);
 
   /* Extract some meta data from the svg handle.  */
   width     = gdk_pixbuf_get_width (pixbuf);
@@ -10210,6 +10242,8 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
     g_object_unref (rsvg_handle);
   if (wrapped_contents)
     xfree (wrapped_contents);
+  if (css)
+    xfree (css);
   /* 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);
-- 
2.29.2


  reply	other threads:[~2021-03-15 21:34 UTC|newest]

Thread overview: 61+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-11 16:51 bug#47074: Replace XPM icons with Unicode codepoints in customize/widgets Stefan Kangas
2021-03-11 17:01 ` Lars Ingebrigtsen
2021-03-11 17:22   ` Stefan Kangas
2021-03-11 17:38   ` Eli Zaretskii
2021-03-11 17:51     ` Stefan Kangas
2021-03-11 19:59       ` Eli Zaretskii
2021-03-11 17:28 ` Eli Zaretskii
2021-03-11 17:51   ` Stefan Kangas
2021-03-11 18:03     ` Lars Ingebrigtsen
2021-03-11 20:21       ` Eli Zaretskii
2021-03-11 20:27         ` Lars Ingebrigtsen
2021-03-12  1:38           ` Stefan Kangas
2021-03-12  1:43             ` Lars Ingebrigtsen
2021-03-12  2:24               ` Stefan Kangas
2021-03-12  2:34                 ` Lars Ingebrigtsen
2021-03-12  8:12             ` Eli Zaretskii
2021-03-11 20:01     ` Eli Zaretskii
2021-03-11 23:49       ` Alan Third
2021-03-12  0:12         ` Lars Ingebrigtsen
2021-03-12 18:21           ` Alan Third
2021-03-12  7:27         ` Eli Zaretskii
2021-03-12 18:25           ` Alan Third
2021-03-12 18:37             ` Eli Zaretskii
2021-03-12 18:43               ` Alan Third
2021-03-12 19:27                 ` Eli Zaretskii
2021-03-13  2:44         ` Stefan Kangas
2021-03-13  7:29           ` Eli Zaretskii
2021-03-13  7:47             ` Stefan Kangas
2021-03-13  8:37               ` Eli Zaretskii
2021-03-13 10:35                 ` Stefan Kangas
2021-03-13 10:54                   ` Eli Zaretskii
2021-03-13 11:51                     ` Stefan Kangas
2021-03-13 16:27                       ` Eli Zaretskii
2021-03-13 16:44                         ` Stefan Kangas
2021-03-13 17:02                           ` Eli Zaretskii
2021-03-13 20:24           ` Alan Third
2021-03-14 13:46           ` Alan Third
2021-03-14 18:44             ` Stefan Kangas
2021-03-14 18:49               ` Eli Zaretskii
2021-03-14 19:37                 ` Alan Third
2021-03-14 19:52                   ` Eli Zaretskii
2021-03-15 21:34                     ` Alan Third [this message]
2021-03-16  3:29                       ` Eli Zaretskii
2021-04-03 20:06                         ` Stefan Kangas
2021-04-03 22:28                           ` Alan Third
2021-04-04  9:21                             ` Stefan Kangas
2021-04-04 11:37                             ` Eli Zaretskii
2021-04-04 11:44                               ` Alan Third
2021-04-04 11:55                                 ` Eli Zaretskii
2021-04-04  6:55                           ` Eli Zaretskii
2021-04-04  9:21                             ` Stefan Kangas
2021-04-04 11:13                               ` Eli Zaretskii
2021-04-04 11:37                                 ` Alan Third
2021-04-04 11:48                                   ` Eli Zaretskii
2021-04-04 12:38                                     ` Eli Zaretskii
2021-04-04 13:15                                       ` Alan Third
2021-04-04 13:14                                     ` Alan Third
2021-04-04 13:22                                       ` Eli Zaretskii
2021-04-04 13:28                                         ` Alan Third
2021-04-04 13:36                                           ` Eli Zaretskii
2021-04-04 11:39                                 ` Stefan Kangas

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=YE/S4DJlJMvGMCG+@breton.holly.idiocy.org \
    --to=alan@idiocy.org \
    --cc=47074@debbugs.gnu.org \
    --cc=eliz@gnu.org \
    --cc=stefan@marxist.se \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).