unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#40845: SVG rendering issues
@ 2020-04-25 12:19 Clément Pit-Claudel
  2020-04-25 14:34 ` Pip Cet
  0 siblings, 1 reply; 52+ messages in thread
From: Clément Pit-Claudel @ 2020-04-25 12:19 UTC (permalink / raw)
  To: 40845

Hi all,

As discussed on the mailing list, a number of issues currently exist with our SVG rendering implementation.  I have tried to summarize the ones I'm aware of in the following example.

(with-current-buffer (get-buffer-create "*svg bugs*")
  (erase-buffer)
  (require 'face-remap)
  (setq text-scale-mode-amount 10)
  (text-scale-mode)
  (let ((svg (svg-create 16 16)))
    (svg-ellipse svg 8 8 4 4)
    (insert "Text: ")
    (print (svg-image svg :ascent 100))
    (insert-image (svg-image svg :ascent 100))
    (insert-image (svg-image svg :scale 5.0 :ascent 'center :foreground "red" :background "darkgreen"))
    (add-text-properties
     (point-min) (point-max)
     '(face (:foreground "orange" :background "purple")
            mouse-face '(:foreground "purple" :background "orange"))))
  (pop-to-buffer (current-buffer)))

The issues:

1. Manually scaling an image, as is done for the second image, doesn't re-render the svg: is scales the bitmap-rendered version of it, causing blurriness.
2. The SVG images don't inherit the background of the current face; instead, they inherit the background of the default face.
3. The SVG images don't inherit the foreground of the current face; instead, they use a black foreground.
4. The :foreground keyword has no effect on svg images.
5. The images are not scaled with the text: changing text-scale-mode-amount doesn't change the size of the images.

For 1, 2, 3, and 4, the expected behavior is easy to define:
- For 1, the image should be scaled before being rasterized. 
- For 2 and 3, the image should inherit the characteristics of the current face, and be re-rendered if that face changes (e.g. when mouse-face applies, which is important for buttons)
- For 4, the :foreground property should be respected

For 5, it's a bit trickier.  One option would be to accept a float-valued :height specification and treat that as a multiple of the current font size.

A partial workaround for 2 is to add an explicit :background, but it doesn't help with face changes, such as applying a mouse-face.  For 1 and 5 it can be enough to set the size in the SVG and add hooks, but that only works easily for SVGs created within emacs.  For 3 and 4, I don't know of a workaround except modifying the SVG.

Cheers,
Clément.





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-04-25 12:19 bug#40845: SVG rendering issues Clément Pit-Claudel
@ 2020-04-25 14:34 ` Pip Cet
  2020-04-25 15:30   ` Eli Zaretskii
  2020-04-25 15:46   ` Eli Zaretskii
  0 siblings, 2 replies; 52+ messages in thread
From: Pip Cet @ 2020-04-25 14:34 UTC (permalink / raw)
  To: Clément Pit-Claudel; +Cc: 40845

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

On Sat, Apr 25, 2020 at 12:20 PM Clément Pit-Claudel
<cpitclaudel@gmail.com> wrote:
>
> Hi all,
>
> As discussed on the mailing list, a number of issues currently exist with our SVG rendering implementation.  I have tried to summarize the ones I'm aware of in the following example.
>
> (with-current-buffer (get-buffer-create "*svg bugs*")
>   (erase-buffer)
>   (require 'face-remap)
>   (setq text-scale-mode-amount 10)
>   (text-scale-mode)
>   (let ((svg (svg-create 16 16)))
>     (svg-ellipse svg 8 8 4 4)
>     (insert "Text: ")
>     (print (svg-image svg :ascent 100))
>     (insert-image (svg-image svg :ascent 100))
>     (insert-image (svg-image svg :scale 5.0 :ascent 'center :foreground "red" :background "darkgreen"))
>     (add-text-properties
>      (point-min) (point-max)
>      '(face (:foreground "orange" :background "purple")
>             mouse-face '(:foreground "purple" :background "orange"))))
>   (pop-to-buffer (current-buffer)))
>
> The issues:
>
> 1. Manually scaling an image, as is done for the second image, doesn't re-render the svg: is scales the bitmap-rendered version of it, causing blurriness.
> 2. The SVG images don't inherit the background of the current face; instead, they inherit the background of the default face.
> 3. The SVG images don't inherit the foreground of the current face; instead, they use a black foreground.
> 4. The :foreground keyword has no effect on svg images.
> 5. The images are not scaled with the text: changing text-scale-mode-amount doesn't change the size of the images.

I would like to add

6. When the cursor is over an SVG image, it is displayed with a box
around it rather than with inverted video as characters are.

I've played around a while ago in an attempt to fix these issues, and
be able to define "character-like" SVG glyphs. My approach was to add
a display spec of the form (gen FN), which calls FN with the current
face parameters as arguments whenever redisplaying the spec, then uses
the return value (an image spec) as the actual spec to be displayed.

It's probably quite slow, but (as of June last) it works, even when
displaying the same buffer twice. Calling elisp from the redisplay
engine is, of course, something we don't really want to have more of,
but we'd do so anyway for a `when' spec (in fact, an alternative
approach to get this working with old Emacsen was to abuse a `when'
spec to set the image spec correctly).

The attached patch, IIRC, is the main part. As you can see, it leaves
most of the work to the Lisp side of things. It can fix all issues
mentioned above by modifying the SVG as required.

Also, IIRC, 3 is an rsvg issue.

[-- Attachment #2: gen.diff --]
[-- Type: text/x-patch, Size: 3137 bytes --]

commit 0af1850485f3ad1519e52de2b1694efa922917f4
Author: Pip Cet <pipcet@gmail.com>
Date:   Sat Jun 22 07:53:28 2019 +0000

    snapshot

diff --git a/src/callint.c b/src/callint.c
index 88a3c348d0..6f2e5d5066 100644
--- a/src/callint.c
+++ b/src/callint.c
@@ -824,6 +824,7 @@ syms_of_callint (void)
   DEFSYM (Qlet, "let");
   DEFSYM (Qif, "if");
   DEFSYM (Qwhen, "when");
+  DEFSYM (Qgen, "gen");
   DEFSYM (Qletx, "let*");
   DEFSYM (Qsave_excursion, "save-excursion");
   DEFSYM (Qprogn, "progn");
diff --git a/src/xdisp.c b/src/xdisp.c
index 5699aac61b..717fb30ec3 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -2728,7 +2728,6 @@ safe_call2 (Lisp_Object fn, Lisp_Object arg1, Lisp_Object arg2)
   return safe_call (3, fn, arg1, arg2);
 }
 
-
 \f
 /***********************************************************************
 			      Debugging
@@ -4893,6 +4892,7 @@ handle_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
 #endif
       && !EQ (XCAR (spec), Qspace)
       && !EQ (XCAR (spec), Qwhen)
+      && !EQ (XCAR (spec), Qgen)
       && !EQ (XCAR (spec), Qslice)
       && !EQ (XCAR (spec), Qspace_width)
       && !EQ (XCAR (spec), Qheight)
@@ -4991,6 +4991,8 @@ display_prop_end (struct it *it, Lisp_Object object, struct text_pos start_pos)
    Value is non-zero if something was found which replaces the display
    of buffer or string text.  */
 
+extern Lisp_Object *lface_id_to_name;
+
 static int
 handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
 			    Lisp_Object overlay, struct text_pos *position,
@@ -5002,6 +5004,46 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
   struct text_pos start_pos = *position;
   void *itdata = NULL;
 
+  if (it != NULL &&
+      CONSP (spec) &&
+      EQ (XCAR (spec), Qgen))
+    {
+      spec = XCDR (spec);
+      if (!CONSP (spec))
+	return 0;
+      Lisp_Object gen = XCAR (spec);
+      struct face *face = FACE_FROM_ID (it->f, it->face_id);
+      Lisp_Object lface = Qnil;
+      Lisp_Object props[] = {
+	QCtype,
+	QCfamily,
+	QCfoundry,
+	QCwidth,
+	QCheight,
+	QCweight,
+	QCslant,
+	QCunderline,
+	QCinverse_video,
+	QCforeground,
+	QCbackground,
+	QCstipple,
+	QCoverline,
+	QCstrike_through,
+	QCbox,
+	QCfont,
+	QCinherit,
+	QCfontset,
+	QCdistant_foreground,
+      };
+      for (int i = 0; i < LFACE_VECTOR_SIZE; i++)
+	lface = Fcons (Fcons (props[i], face->lface[i]),
+		       lface);
+      Lisp_Object font = Qnil;
+      XSETFONT (font, face->font);
+      lface = Fcons (Fcons (QCfont, font), lface);
+      spec = safe_call1 (gen, lface);
+    }
+
   /* If SPEC is a list of the form `(when FORM . VALUE)', evaluate FORM.
      If the result is non-nil, use VALUE instead of SPEC.  */
   form = Qt;
diff --git a/src/xfaces.c b/src/xfaces.c
index 012cc96470..47453c2b31 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -294,7 +294,7 @@ #define FACE_CACHE_BUCKETS_SIZE 1001
 
 /* A vector mapping Lisp face Id's to face names.  */
 
-static Lisp_Object *lface_id_to_name;
+Lisp_Object *lface_id_to_name;
 static ptrdiff_t lface_id_to_name_size;
 
 #ifdef HAVE_WINDOW_SYSTEM


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-04-25 14:34 ` Pip Cet
@ 2020-04-25 15:30   ` Eli Zaretskii
  2020-04-25 15:48     ` Pip Cet
  2020-04-25 15:46   ` Eli Zaretskii
  1 sibling, 1 reply; 52+ messages in thread
From: Eli Zaretskii @ 2020-04-25 15:30 UTC (permalink / raw)
  To: Pip Cet; +Cc: cpitclaudel, 40845

> From: Pip Cet <pipcet@gmail.com>
> Date: Sat, 25 Apr 2020 14:34:11 +0000
> Cc: 40845@debbugs.gnu.org
> 
> 6. When the cursor is over an SVG image, it is displayed with a box
> around it rather than with inverted video as characters are.
> 
> I've played around a while ago in an attempt to fix these issues, and
> be able to define "character-like" SVG glyphs. My approach was to add
> a display spec of the form (gen FN), which calls FN with the current
> face parameters as arguments whenever redisplaying the spec, then uses
> the return value (an image spec) as the actual spec to be displayed.

I don't think I understand why we need to call a function for this.
This is about displaying an image with a specific background color,
isn't it?





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-04-25 14:34 ` Pip Cet
  2020-04-25 15:30   ` Eli Zaretskii
@ 2020-04-25 15:46   ` Eli Zaretskii
  2020-04-25 16:42     ` Clément Pit-Claudel
  1 sibling, 1 reply; 52+ messages in thread
From: Eli Zaretskii @ 2020-04-25 15:46 UTC (permalink / raw)
  To: Pip Cet; +Cc: cpitclaudel, 40845

> From: Pip Cet <pipcet@gmail.com>
> Date: Sat, 25 Apr 2020 14:34:11 +0000
> Cc: 40845@debbugs.gnu.org
> 
> > 3. The SVG images don't inherit the foreground of the current face; instead, they use a black foreground.
> 
> Also, IIRC, 3 is an rsvg issue.

I don't think I understand what item 3 is complaining about.  If I
visit etc/images/splash.svg, it gets the background color of the
default face.  So is the complaint that it takes the background from
the default face instead of the current face?  That should be easy to
fix, I think, as this code in svg_load_image shows:

    Emacs_Color background;
    Lisp_Object specified_bg = image_spec_value (img->spec, QCbackground, NULL);
    if (!STRINGP (specified_bg)
	|| !FRAME_TERMINAL (f)->defined_color_hook (f,
                                                    SSDATA (specified_bg),
                                                    &background,
                                                    false,
                                                    false))
      FRAME_TERMINAL (f)->query_frame_background_color (f, &background);





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-04-25 15:30   ` Eli Zaretskii
@ 2020-04-25 15:48     ` Pip Cet
  2020-04-25 16:10       ` Eli Zaretskii
  0 siblings, 1 reply; 52+ messages in thread
From: Pip Cet @ 2020-04-25 15:48 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: cpitclaudel, 40845

On Sat, Apr 25, 2020 at 3:30 PM Eli Zaretskii <eliz@gnu.org> wrote:
> > I've played around a while ago in an attempt to fix these issues, and
> > be able to define "character-like" SVG glyphs. My approach was to add
> > a display spec of the form (gen FN), which calls FN with the current
> > face parameters as arguments whenever redisplaying the spec, then uses
> > the return value (an image spec) as the actual spec to be displayed.
>
> I don't think I understand why we need to call a function for this.
> This is about displaying an image with a specific background color,
> isn't it?

Even if the problem were just the choice of background color, that
would require significant and non-trivial changes for some cases: for
example, an emoji might have to choose foreground colors that provide
sufficient contrast to the background color, and antialiasing and
sub-pixel rendering would also need to be taken into account.

But, at least for me, it's not: I want to be able to define something
that behaves like a character, including displaying differently in
different frames and depending on different face parameters such as
weight, slant, and RTL-ness. I don't really see a way of doing that
satisfactorily without invoking user code outside of the display
engine/image backend code.





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-04-25 15:48     ` Pip Cet
@ 2020-04-25 16:10       ` Eli Zaretskii
  2020-04-25 17:38         ` Pip Cet
  0 siblings, 1 reply; 52+ messages in thread
From: Eli Zaretskii @ 2020-04-25 16:10 UTC (permalink / raw)
  To: Pip Cet; +Cc: cpitclaudel, 40845

> From: Pip Cet <pipcet@gmail.com>
> Date: Sat, 25 Apr 2020 15:48:39 +0000
> Cc: cpitclaudel@gmail.com, 40845@debbugs.gnu.org
> 
> On Sat, Apr 25, 2020 at 3:30 PM Eli Zaretskii <eliz@gnu.org> wrote:
> >
> > I don't think I understand why we need to call a function for this.
> > This is about displaying an image with a specific background color,
> > isn't it?
> 
> Even if the problem were just the choice of background color, that
> would require significant and non-trivial changes for some cases: for
> example, an emoji might have to choose foreground colors that provide
> sufficient contrast to the background color, and antialiasing and
> sub-pixel rendering would also need to be taken into account.

We are talking about displaying images, not characters, right?  So why
are emoji relevant to this?

> I want to be able to define something that behaves like a character,
> including displaying differently in different frames and depending
> on different face parameters such as weight, slant, and RTL-ness.

All of that is possible with images, so I don't think I understand why
we need to handle this as a character.  This very bug report was filed
because I said we shouldn't use characters and fonts for these
purposes, so let's not discuss that alternative, please, at least not
here.





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-04-25 15:46   ` Eli Zaretskii
@ 2020-04-25 16:42     ` Clément Pit-Claudel
  2020-04-25 17:02       ` Eli Zaretskii
  0 siblings, 1 reply; 52+ messages in thread
From: Clément Pit-Claudel @ 2020-04-25 16:42 UTC (permalink / raw)
  To: Eli Zaretskii, Pip Cet; +Cc: 40845

On 25/04/2020 11.46, Eli Zaretskii wrote:
>> From: Pip Cet <pipcet@gmail.com>
>> Date: Sat, 25 Apr 2020 14:34:11 +0000
>> Cc: 40845@debbugs.gnu.org
>>
>>> 3. The SVG images don't inherit the foreground of the current face; instead, they use a black foreground.
>>
>> Also, IIRC, 3 is an rsvg issue.
> 
> I don't think I understand what item 3 is complaining about.  If I
> visit etc/images/splash.svg, it gets the background color of the
> default face.  So is the complaint that it takes the background from
> the default face instead of the current face?  That should be easy to
> fix, I think, as this code in svg_load_image shows:

That's item 2:

  2. The SVG images don't inherit the background of the current face; instead, they inherit the background of the default face.

and you summarized it exactly right.  Item 3 is about the color of the circle that the repro draws. . It should be purple, but it's black.

Clément.





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-04-25 16:42     ` Clément Pit-Claudel
@ 2020-04-25 17:02       ` Eli Zaretskii
  2020-04-25 17:24         ` Clément Pit-Claudel
  0 siblings, 1 reply; 52+ messages in thread
From: Eli Zaretskii @ 2020-04-25 17:02 UTC (permalink / raw)
  To: Clément Pit-Claudel; +Cc: 40845, pipcet

> Cc: 40845@debbugs.gnu.org
> From: Clément Pit-Claudel <cpitclaudel@gmail.com>
> Date: Sat, 25 Apr 2020 12:42:07 -0400
> 
> >>> 3. The SVG images don't inherit the foreground of the current face; instead, they use a black foreground.
> >>
> >> Also, IIRC, 3 is an rsvg issue.
> > 
> > I don't think I understand what item 3 is complaining about.  If I
> > visit etc/images/splash.svg, it gets the background color of the
> > default face.  So is the complaint that it takes the background from
> > the default face instead of the current face?  That should be easy to
> > fix, I think, as this code in svg_load_image shows:
> 
> That's item 2:
> 
>   2. The SVG images don't inherit the background of the current face; instead, they inherit the background of the default face.
> 
> and you summarized it exactly right.  Item 3 is about the color of the circle that the repro draws. . It should be purple, but it's black.

Ah, sorry.

But IMO the foreground of an image shouldn't be affected by the
current face's foreground.  Images should come with their own colors,
and be displayed like that.  I think in the context of the discussion
that led to this bug report it's actually almost a must: we want
images with attractive colors to serve as the icons, we don't want
them to be affected by whatever face happens to be nearby.





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-04-25 17:02       ` Eli Zaretskii
@ 2020-04-25 17:24         ` Clément Pit-Claudel
  2020-04-25 17:46           ` Alan Third
  0 siblings, 1 reply; 52+ messages in thread
From: Clément Pit-Claudel @ 2020-04-25 17:24 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 40845, pipcet

On 25/04/2020 13.02, Eli Zaretskii wrote:
> IMO the foreground of an image shouldn't be affected by the
> current face's foreground.  Images should come with their own colors,
> and be displayed like that.  I think in the context of the discussion
> that led to this bug report it's actually almost a must: we want
> images with attractive colors to serve as the icons, we don't want
> them to be affected by whatever face happens to be nearby.

Yes, of course: if an image has a foreground color, it should be respected.
But it's not uncommon for SVG images to not include a foreground color, as shown in the repro.  In that case, the image should use the current foreground color, I think.
(of course, a :foreground keyword, if any, should take precedence; that is issue 4).






^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-04-25 16:10       ` Eli Zaretskii
@ 2020-04-25 17:38         ` Pip Cet
  2020-04-25 18:07           ` Eli Zaretskii
  0 siblings, 1 reply; 52+ messages in thread
From: Pip Cet @ 2020-04-25 17:38 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: cpitclaudel, 40845

On Sat, Apr 25, 2020 at 4:10 PM Eli Zaretskii <eliz@gnu.org> wrote:
> > From: Pip Cet <pipcet@gmail.com>
> > Date: Sat, 25 Apr 2020 15:48:39 +0000
> > Cc: cpitclaudel@gmail.com, 40845@debbugs.gnu.org
> >
> > On Sat, Apr 25, 2020 at 3:30 PM Eli Zaretskii <eliz@gnu.org> wrote:
> > >
> > > I don't think I understand why we need to call a function for this.
> > > This is about displaying an image with a specific background color,
> > > isn't it?
> >
> > Even if the problem were just the choice of background color, that
> > would require significant and non-trivial changes for some cases: for
> > example, an emoji might have to choose foreground colors that provide
> > sufficient contrast to the background color, and antialiasing and
> > sub-pixel rendering would also need to be taken into account.
>
> We are talking about displaying images, not characters, right?

Correct: images which behave like character glyphs, but don't actually
have character codepoints, and aren't implemented by fonts.

> So why are emoji relevant to this?

An emoji is an example of an image which needs to know face properties
to blend in, or stick out, or whatever it is people who use them want
to happen. The intention was not that you'd use an emoji codepoint and
a font providing a character for that codepoint, which is a silly way
of implementing emoji.

> > I want to be able to define something that behaves like a character,
> > including displaying differently in different frames and depending
> > on different face parameters such as weight, slant, and RTL-ness.
>
> All of that is possible with images, so I don't think I understand why
> we need to handle this as a character.

Yes, my approach uses images, and no, it doesn't "handle this as a
character". It makes the glyph's apparent behavior match that of
character glyphs, while actually displaying an image spec which
changes with the properties of surrounding text, etc.

> This very bug report was filed
> because I said we shouldn't use characters and fonts for these
> purposes, so let's not discuss that alternative, please, at least not
> here.

No one was.





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-04-25 17:24         ` Clément Pit-Claudel
@ 2020-04-25 17:46           ` Alan Third
  2020-04-25 18:07             ` Pip Cet
  2020-04-26 21:17             ` Alan Third
  0 siblings, 2 replies; 52+ messages in thread
From: Alan Third @ 2020-04-25 17:46 UTC (permalink / raw)
  To: Clément Pit-Claudel; +Cc: 40845, pipcet

On Sat, Apr 25, 2020 at 01:24:13PM -0400, Clément Pit-Claudel wrote:
> On 25/04/2020 13.02, Eli Zaretskii wrote:
> > IMO the foreground of an image shouldn't be affected by the
> > current face's foreground.  Images should come with their own colors,
> > and be displayed like that.  I think in the context of the discussion
> > that led to this bug report it's actually almost a must: we want
> > images with attractive colors to serve as the icons, we don't want
> > them to be affected by whatever face happens to be nearby.
> 
> Yes, of course: if an image has a foreground color, it should be
> respected. But it's not uncommon for SVG images to not include a
> foreground color, as shown in the repro. In that case, the image
> should use the current foreground color, I think. (of course, a
> :foreground keyword, if any, should take precedence; that is issue
> 4).

Lars fixed the foreground issue for eww by wrapping svg files in
another svg. See svg--wrap-svg in shr.el (bug#37159).

I think this is the only practical way to handle svg files with no
foreground colour set. To do this when loading _any_ svg we’d probably
have to move it into create-image or image.c.
-- 
Alan Third





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-04-25 17:38         ` Pip Cet
@ 2020-04-25 18:07           ` Eli Zaretskii
  2020-04-25 19:41             ` Pip Cet
  0 siblings, 1 reply; 52+ messages in thread
From: Eli Zaretskii @ 2020-04-25 18:07 UTC (permalink / raw)
  To: Pip Cet; +Cc: cpitclaudel, 40845

> From: Pip Cet <pipcet@gmail.com>
> Date: Sat, 25 Apr 2020 17:38:31 +0000
> Cc: cpitclaudel@gmail.com, 40845@debbugs.gnu.org
> 
> Correct: images which behave like character glyphs, but don't actually
> have character codepoints, and aren't implemented by fonts.
> 
> > So why are emoji relevant to this?
> 
> An emoji is an example of an image which needs to know face properties
> to blend in, or stick out, or whatever it is people who use them want
> to happen. The intention was not that you'd use an emoji codepoint and
> a font providing a character for that codepoint, which is a silly way
> of implementing emoji.
> 
> > > I want to be able to define something that behaves like a character,
> > > including displaying differently in different frames and depending
> > > on different face parameters such as weight, slant, and RTL-ness.
> >
> > All of that is possible with images, so I don't think I understand why
> > we need to handle this as a character.
> 
> Yes, my approach uses images, and no, it doesn't "handle this as a
> character". It makes the glyph's apparent behavior match that of
> character glyphs, while actually displaying an image spec which
> changes with the properties of surrounding text, etc.
> 
> > This very bug report was filed
> > because I said we shouldn't use characters and fonts for these
> > purposes, so let's not discuss that alternative, please, at least not
> > here.
> 
> No one was.

Then I guess I don't understand your implementation at all.





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-04-25 17:46           ` Alan Third
@ 2020-04-25 18:07             ` Pip Cet
  2020-04-26 21:17             ` Alan Third
  1 sibling, 0 replies; 52+ messages in thread
From: Pip Cet @ 2020-04-25 18:07 UTC (permalink / raw)
  To: Alan Third, Clément Pit-Claudel, Eli Zaretskii, 40845,
	pipcet

On Sat, Apr 25, 2020 at 5:46 PM Alan Third <alan@idiocy.org> wrote:
> On Sat, Apr 25, 2020 at 01:24:13PM -0400, Clément Pit-Claudel wrote:
> > Yes, of course: if an image has a foreground color, it should be
> > respected. But it's not uncommon for SVG images to not include a
> > foreground color, as shown in the repro. In that case, the image
> > should use the current foreground color, I think. (of course, a
> > :foreground keyword, if any, should take precedence; that is issue
> > 4).

For reference, the relevant chunk of librsvg source code is this:

// https://www.w3.org/TR/SVG/color.html#ColorProperty
make_property!(
    ComputedValues,
    Color,
    // The SVG spec allows the user agent to choose its own default
for the "color" property.
    // We don't allow passing in an initial CSS in the public API, so
we'll start with black.
    //
    // See https://bugzilla.gnome.org/show_bug.cgi?id=764808 for a
case where this would
    // be useful - rendering equations with currentColor, so they take
on the color of the
    // surrounding text.
    default: cssparser::RGBA::new(0, 0, 0, 0xff),
    inherits_automatically: true,
    newtype_parse: cssparser::RGBA,
);

> Lars fixed the foreground issue for eww by wrapping svg files in
> another svg. See svg--wrap-svg in shr.el (bug#37159).
>
> I think this is the only practical way to handle svg files with no
> foreground colour set. To do this when loading _any_ svg we’d probably
> have to move it into create-image or image.c.

I think it's a neat hack, but it's just one of the more obvious ways
of working around an annoying limitation of librsvg (Ideally, we'd use
a library without such a limitation by default and fall back to
modifying/wrapping SVGs when using a limited library.)

For applications which change glyphs' foreground colors a lot, it
might be preferrable to coax rsvg into providing an alpha-only map for
the foreground plus an RGBA map for the background and blend them
together, and that approach would work for other image types.





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-04-25 18:07           ` Eli Zaretskii
@ 2020-04-25 19:41             ` Pip Cet
  2020-04-25 20:11               ` Eli Zaretskii
  0 siblings, 1 reply; 52+ messages in thread
From: Pip Cet @ 2020-04-25 19:41 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: cpitclaudel, 40845

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

On Sat, Apr 25, 2020 at 6:07 PM Eli Zaretskii <eliz@gnu.org> wrote:
or these
> Then I guess I don't understand your implementation at all.

My use case is to include a glyph which is supposed to look like a
character, but doesn't actually have a unicode codepoint. (I'm sorry
if this differs from the use cases you're exclusively concerned with,
but it appeared to be relevant enough to Clément's problem that I
assumed he was having a similar issue).

That means that we want to use an image spec, not a character in a
font; but that image spec depends on face/font properties, because we
want to blend in with surrounding text. The most obvious ones are
foreground and background color and size, but slant and weight would
also affect properly-rendered character-like images.

It seems fairly obvious to me that it's a bad idea to do all the work
in the display engine or in C code: sub-pixel rendering and
anti-aliasing are hard to get right. A character-like glyph might need
a third color which provides sufficient contrast to the foreground and
background colors, and that color space calculation is complicated
enough to be moved to Lisp.

So I moved it to Lisp: there's Lisp code which is passed the font/face
properties, and returns an image spec that's appropriate for that.

The attached patch actually applies to and works with master, and
includes an example. It can no longer easily be demonstrated to do the
right thing when the same buffer is displayed in different frames,
because Emacs currently applies text scaling per buffer rather than
per frame (IMHO, that's a bug). It also doesn't properly display the
cursor as a block cursor when it's over the glyph, because I can no
longer find the code which allowed me to tell, from Lisp, whether that
was the case.

And of course it doesn't use the right font metrics, because these
currently aren't exposed to Lisp.

But all these limitations are fixable.

[-- Attachment #2: 0001-support-generated-display-specs.patch --]
[-- Type: text/x-patch, Size: 4818 bytes --]

From 8e7aa38e098bd044a71fa20df1593d2b37347f1c Mon Sep 17 00:00:00 2001
From: Pip Cet <pipcet@gmail.com>
Date: Sat, 25 Apr 2020 18:41:02 +0000
Subject: [PATCH] support generated display specs

---
 generated-image-specs.el | 31 ++++++++++++++++++++++++++++
 src/callint.c            |  1 +
 src/xdisp.c              | 44 ++++++++++++++++++++++++++++++++++++++++
 src/xfaces.c             |  2 +-
 4 files changed, 77 insertions(+), 1 deletion(-)
 create mode 100644 generated-image-specs.el

diff --git a/generated-image-specs.el b/generated-image-specs.el
new file mode 100644
index 0000000000..b764d1999d
--- /dev/null
+++ b/generated-image-specs.el
@@ -0,0 +1,31 @@
+(require 'svg)
+
+(defun generate-circle-image (alist)
+  (let* ((vsize (font-get (alist-get :font alist) :size))
+         (foreground (apply #'color-rgb-to-hex (nconc (color-name-to-rgb (alist-get :foreground alist)) (list 2))))
+         (background (apply #'color-rgb-to-hex (nconc (color-name-to-rgb (alist-get :background alist)) (list 2))))
+         (hsize (* vsize .8))
+         (svg (svg-create hsize vsize))
+         (sw (* .1 hsize)))
+    (svg-rectangle svg 0 0 hsize vsize :fill background)
+    (svg-circle svg (* hsize .5)
+                (- (* .8 vsize) (* .5 hsize))
+                (- (* hsize .5) sw)
+                :fill "none"
+                :stroke foreground
+                :stroke-width sw)
+    (svg-line svg
+              (* hsize .5) (- (* .8 vsize) (* .5 hsize))
+              (* hsize .5) (- (* .8 vsize) sw)
+              :stroke foreground
+              :stroke-width sw)
+    (svg-circle svg (* hsize .5) (- (* .8 vsize) (* (/ 2.0 3.0) hsize))
+                sw
+                :fill foreground
+                :stroke "none")
+    (let ((ret (svg-image svg)))
+      (setcdr ret (plist-put (cdr ret) :scale 1.0))
+      (setcdr ret (plist-put (cdr ret) :ascent 80))
+      ret)))
+
+(insert (propertize " " 'display `(generated-spec ,#'generate-circle-image)))
diff --git a/src/callint.c b/src/callint.c
index eb916353a0..2c34dddbe4 100644
--- a/src/callint.c
+++ b/src/callint.c
@@ -826,6 +826,7 @@ syms_of_callint (void)
   DEFSYM (Qlet, "let");
   DEFSYM (Qif, "if");
   DEFSYM (Qwhen, "when");
+  DEFSYM (Qgenerated_spec, "generated-spec");
   DEFSYM (Qletx, "let*");
   DEFSYM (Qsave_excursion, "save-excursion");
   DEFSYM (Qprogn, "progn");
diff --git a/src/xdisp.c b/src/xdisp.c
index 3258893956..b341cbb735 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -5050,6 +5050,7 @@ handle_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
 #endif
       && !EQ (XCAR (spec), Qspace)
       && !EQ (XCAR (spec), Qwhen)
+      && !EQ (XCAR (spec), Qgenerated_spec)
       && !EQ (XCAR (spec), Qslice)
       && !EQ (XCAR (spec), Qspace_width)
       && !EQ (XCAR (spec), Qheight)
@@ -5148,6 +5149,8 @@ display_prop_end (struct it *it, Lisp_Object object, struct text_pos start_pos)
    Value is non-zero if something was found which replaces the display
    of buffer or string text.  */
 
+extern Lisp_Object *lface_id_to_name;
+
 static int
 handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
 			    Lisp_Object overlay, struct text_pos *position,
@@ -5159,6 +5162,47 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
   struct text_pos start_pos = *position;
   void *itdata = NULL;
 
+  if (it != NULL &&
+      CONSP (spec) &&
+      EQ (XCAR (spec), Qgenerated_spec))
+    {
+      spec = XCDR (spec);
+      if (!CONSP (spec))
+	return 0;
+      Lisp_Object gen = XCAR (spec);
+      struct face *face = FACE_FROM_ID (it->f, it->face_id);
+      Lisp_Object lface = Qnil;
+      Lisp_Object props[] = {
+	QCtype,
+	QCfamily,
+	QCfoundry,
+	QCwidth,
+	QCheight,
+	QCweight,
+	QCslant,
+	QCunderline,
+	QCinverse_video,
+	QCforeground,
+	QCbackground,
+	QCstipple,
+	QCoverline,
+	QCstrike_through,
+	QCbox,
+	QCfont,
+	QCinherit,
+	QCfontset,
+	QCdistant_foreground,
+	QCextend,
+      };
+      for (int i = 0; i < LFACE_VECTOR_SIZE; i++)
+	lface = Fcons (Fcons (props[i], face->lface[i]),
+		       lface);
+      Lisp_Object font = Qnil;
+      XSETFONT (font, face->font);
+      lface = Fcons (Fcons (QCfont, font), lface);
+      spec = safe_call1 (gen, lface);
+    }
+
   /* If SPEC is a list of the form `(when FORM . VALUE)', evaluate FORM.
      If the result is non-nil, use VALUE instead of SPEC.  */
   form = Qt;
diff --git a/src/xfaces.c b/src/xfaces.c
index bab142ade0..01429ac86e 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -310,7 +310,7 @@ #define FACE_CACHE_BUCKETS_SIZE 1001
 
 /* A vector mapping Lisp face Id's to face names.  */
 
-static Lisp_Object *lface_id_to_name;
+Lisp_Object *lface_id_to_name;
 static ptrdiff_t lface_id_to_name_size;
 
 #ifdef HAVE_WINDOW_SYSTEM
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-04-25 19:41             ` Pip Cet
@ 2020-04-25 20:11               ` Eli Zaretskii
  2020-04-26 10:15                 ` Pip Cet
  0 siblings, 1 reply; 52+ messages in thread
From: Eli Zaretskii @ 2020-04-25 20:11 UTC (permalink / raw)
  To: Pip Cet; +Cc: cpitclaudel, 40845

> From: Pip Cet <pipcet@gmail.com>
> Date: Sat, 25 Apr 2020 19:41:31 +0000
> Cc: cpitclaudel@gmail.com, 40845@debbugs.gnu.org
> 
> My use case is to include a glyph which is supposed to look like a
> character, but doesn't actually have a unicode codepoint. (I'm sorry
> if this differs from the use cases you're exclusively concerned with,
> but it appeared to be relevant enough to Clément's problem that I
> assumed he was having a similar issue).
> 
> That means that we want to use an image spec, not a character in a
> font; but that image spec depends on face/font properties, because we
> want to blend in with surrounding text. The most obvious ones are
> foreground and background color and size, but slant and weight would
> also affect properly-rendered character-like images.

If we want to display an image, the logical way would be to use an
image spec, which is already supported, enhancing it as needed.  I
don't see anything in the above attributes that would be hard to have
within the existing framework of how we display images.  I don't
really understand how you can make images "slant" or "bold" (unless
they were like that to begin with), or why would we want to, but maybe
there's some way of interpreting that as well.

None of this requires a new spec or calling Lisp.  All of the metrics
of the current face's font are known by the display code, and there
are many that cannot be obtained from Lisp, like the current line
height.  Doing these calculations in Lisp is IMO the worst possible
way of using Lisp callouts from the display engine: this has all the
disadvantages of calling Lisp, and none of the advantages.

> It seems fairly obvious to me that it's a bad idea to do all the work
> in the display engine or in C code: sub-pixel rendering and
> anti-aliasing are hard to get right.

Aren't we talking about displaying existing images, which someone
already prepared while using all those techniques?  Why would the
display engine want or need to modify the image using them?

> A character-like glyph might need a third color which provides
> sufficient contrast to the foreground and background colors, and
> that color space calculation is complicated enough to be moved to
> Lisp.

Within the context of what these icons are supposed to be used for, I
envision the images coming with bright, catchy colors that should be
left alone, not enhanced by color and contrast tweaking of whatever
happens to be the face colors the user wants.  Those who design such
icons do a much better job than any Lisp program.

> But all these limitations are fixable.

They wouldn't have existed if you used the code which displays images.

So I still don't understand the motivation for this approach.  (Read:
I think it's wrong.)





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-04-25 20:11               ` Eli Zaretskii
@ 2020-04-26 10:15                 ` Pip Cet
  2020-04-26 14:38                   ` Eli Zaretskii
  0 siblings, 1 reply; 52+ messages in thread
From: Pip Cet @ 2020-04-26 10:15 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: cpitclaudel, 40845

On Sat, Apr 25, 2020 at 8:11 PM Eli Zaretskii <eliz@gnu.org> wrote:
> > From: Pip Cet <pipcet@gmail.com>
> > Date: Sat, 25 Apr 2020 19:41:31 +0000
> > Cc: cpitclaudel@gmail.com, 40845@debbugs.gnu.org
> >
> > My use case is to include a glyph which is supposed to look like a
> > character, but doesn't actually have a unicode codepoint.
> >
> > That means that we want to use an image spec, not a character in a
> > font; but that image spec depends on face/font properties, because we
> > want to blend in with surrounding text. The most obvious ones are
> > foreground and background color and size, but slant and weight would
> > also affect properly-rendered character-like images.
>
> If we want to display an image, the logical way would be to use an
> image spec, which is already supported, enhancing it as needed.

I want to display a glyph that looks different depending on its
textual context. That means it's not "an image", in the traditional
sense. and enhancing image specs to handle such context-dependent
glyphs is wrong, because it moves code into the image backend that
applies to all image backends.

To be clear, to me "an image" is a compressed way of storing RGBA
information for each pixel in a rectangle. It has no concept of
foreground color or background color or slant or weight.

The enhancement I propose is a layer of indirection, allowing the
image spec itself to be adjusted to face/font properties. Whether or
not it's best to use a Lisp function for that, or a hash table, is
something I'm not clear about yet.

> I don't see anything in the above attributes that would be hard to have
> within the existing framework of how we display images.

I don't see anything in the above attributes that would be possible to
have without major changes to image backends, for features that do not
depend on the image backend.

> I don't
> really understand how you can make images "slant" or "bold" (unless
> they were like that to begin with), or why would we want to, but maybe
> there's some way of interpreting that as well.

Because we want the glyph to blend in with surrounding text. Like a
character. Thus "character-like glyph". It's not an image. My use case
is displaying character-like glyphs, implemented as
dynamically-generated images, not to display final images.

And, no, there's no way for an image backend to interpret that. We
have to use different image specs.

> None of this requires a new spec or calling Lisp.

I don't see how to do it without a new spec. I do see an obvious way
of doing it without calling Lisp, by using, say, a hash table. That's
an implementation detail, and one I'm willing to argue about, but "you
want images, not character-like glyphs" isn't an argument, it's simply
a statement that you don't want my use case to be supported.

> All of the metrics
> of the current face's font are known by the display code, and there
> are many that cannot be obtained from Lisp, like the current line
> height.

Indeed, so the display code has to expose those to Lisp.

> Doing these calculations in Lisp is IMO the worst possible
> way of using Lisp callouts from the display engine: this has all the
> disadvantages of calling Lisp, and none of the advantages.

The advantage is my use case is supported, and with your proposal
(which I don't understand completely, but it appears to be a
perfunctory implementation of "foreground"/"background" colors for
images) it isn't.

Whether we should call Lisp (which would, in practice, return a cached
image spec most of the time) or use a hash table (and we'd have to
somehow trigger Lisp updating that hash table) is something I'm not
clear about. Since we're already calling Lisp from code in the
vicinity, it seems relatively safe to do so.

> > It seems fairly obvious to me that it's a bad idea to do all the work
> > in the display engine or in C code: sub-pixel rendering and
> > anti-aliasing are hard to get right.
>
> Aren't we talking about displaying existing images, which someone
> already prepared while using all those techniques?

I'm talking about displaying character-like glyphs.

> Why would the
> display engine want or need to modify the image using them?

To make the glyph character-like.

> > A character-like glyph might need a third color which provides
> > sufficient contrast to the foreground and background colors, and
> > that color space calculation is complicated enough to be moved to
> > Lisp.
>
> Within the context of what these icons are supposed to be used for, I
> envision the images coming with bright, catchy colors that should be
> left alone, not enhanced by color and contrast tweaking of whatever
> happens to be the face colors the user wants.

I'm not sure which icons you're thinking about, but I certainly don't
want my symbols to have "bright, catchy colors that should be left
alone". That's one valid thing for the Lisp code to do, to leave the
image alone and not modify it, but I want the option to have
character-like glyphs, which look like characters but aren't, and that
means they don't have bright, catchy colors that should be left alone.

> Those who design such
> icons do a much better job than any Lisp program.

That's an end user decision, not something we should assume a priori.

> > But all these limitations are fixable.
> They wouldn't have existed if you used the code which displays images.

I want to display character-like glyphs. I don't see a way doing that
with existing image specs, because the image specs do not depend on
face/font properties. I'm still not sure what you're proposing, but
making images depend in a brutish way on "foreground" and "background"
color is a highly specific and limited solution that doesn't solve my
use case at all.

> So I still don't understand the motivation for this approach.  (Read:
> I think it's wrong.)

I'm still not sure whether you're suggesting anything that would
handle my use case even remotely, or simply saying it's not a use case
that Emacs should be extensible to. I've certainly not seen any
suggestion that would do the former.

But, just to be clear, I posted this code because I'd already made the
minor effort to get a new (and, IMHO, important) Emacs feature to
work. I deliberately decided not to submit it, because while it is a
new, generally useful feature Emacs sorely lacks, there are both
productive discussions to have about it (such as whether it uses a
hash table or a Lisp function calls) and unproductive ones, and the
latter in particular translate to a major effort that I did not at the
time feel was worth it.





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-04-26 10:15                 ` Pip Cet
@ 2020-04-26 14:38                   ` Eli Zaretskii
  2020-04-26 19:00                     ` Pip Cet
  0 siblings, 1 reply; 52+ messages in thread
From: Eli Zaretskii @ 2020-04-26 14:38 UTC (permalink / raw)
  To: Pip Cet; +Cc: cpitclaudel, 40845

> From: Pip Cet <pipcet@gmail.com>
> Date: Sun, 26 Apr 2020 10:15:39 +0000
> Cc: cpitclaudel@gmail.com, 40845@debbugs.gnu.org
> 
> > If we want to display an image, the logical way would be to use an
> > image spec, which is already supported, enhancing it as needed.
> 
> I want to display a glyph that looks different depending on its
> textual context. That means it's not "an image", in the traditional
> sense.

Then I guess we are talking about two different use cases.  This bug
report was filed in the context of this discussion:

  https://lists.gnu.org/archive/html/emacs-devel/2020-04/msg01386.html

where I said that I think such UI effects should be implemented by
using images, not special characters and special fonts.

> and enhancing image specs to handle such context-dependent
> glyphs is wrong, because it moves code into the image backend that
> applies to all image backends.

"Image backend" in this context is the image libraries, like librsvg
and libpng, is that right?  If so, which one of them can do the stuff
Clément reported missing?

> The enhancement I propose is a layer of indirection, allowing the
> image spec itself to be adjusted to face/font properties.

The kind of adjustments that we need for the use case which prompted
this discussion can be done inside the display engine.  Or at least I
don't see a reason why it couldn't be.

> > I don't
> > really understand how you can make images "slant" or "bold" (unless
> > they were like that to begin with), or why would we want to, but maybe
> > there's some way of interpreting that as well.
> 
> Because we want the glyph to blend in with surrounding text. Like a
> character.

Not really, not in the use case discussed here.

> And, no, there's no way for an image backend to interpret that. We
> have to use different image specs.

A Lisp program that prepares such display can prepare the spec
accordingly, if needed.  Any effects that cannot be explicitly
produced by Lisp and we'd need the display code to produce can be
communicated using the image spec keywords, like we always do.  For
example, if we want the image to scale with the surrounding face, we
can have a special value of the :scale attribute.  And similarly with
other attributes; we can also invent new keywords for attributes
currently not supported.

> "you want images, not character-like glyphs" isn't an argument, it's
> simply a statement that you don't want my use case to be supported.

It just means your use case is different from what is being discussed
here, and serves purposes other than those which prompted this bug
report.  I don't think we should mix them.

> I'm talking about displaying character-like glyphs.

And I'm not.  This bug report is about a different use case.

> > Within the context of what these icons are supposed to be used for, I
> > envision the images coming with bright, catchy colors that should be
> > left alone, not enhanced by color and contrast tweaking of whatever
> > happens to be the face colors the user wants.
> 
> I'm not sure which icons you're thinking about, but I certainly don't
> want my symbols to have "bright, catchy colors that should be left
> alone".

I suggest to read the above discussion, and also look at the UI
look-and-feel that is being sought.  You will see many examples there
of the kind of images that people would like to see.  I think their
vivid colors is one of the main aspects that attract users to such UI.

> I'm still not sure whether you're suggesting anything that would
> handle my use case even remotely, or simply saying it's not a use case
> that Emacs should be extensible to.

I guess I'm saying the latter.  Maybe if you explained when such use
cases arise, I will agree with you.  But in any case, it's a different
use case.





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-04-26 14:38                   ` Eli Zaretskii
@ 2020-04-26 19:00                     ` Pip Cet
  2020-04-27 15:47                       ` Eli Zaretskii
  0 siblings, 1 reply; 52+ messages in thread
From: Pip Cet @ 2020-04-26 19:00 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: cpitclaudel, 40845

On Sun, Apr 26, 2020 at 2:38 PM Eli Zaretskii <eliz@gnu.org> wrote:
> > From: Pip Cet <pipcet@gmail.com>
> > Date: Sun, 26 Apr 2020 10:15:39 +0000
> > Cc: cpitclaudel@gmail.com, 40845@debbugs.gnu.org
> >
> > > If we want to display an image, the logical way would be to use an
> > > image spec, which is already supported, enhancing it as needed.
> >
> > I want to display a glyph that looks different depending on its
> > textual context. That means it's not "an image", in the traditional
> > sense.
>
> Then I guess we are talking about two different use cases.

A more general one, and a more limited and specific one. As it
happens, the fix for the more general one is simpler.

> This bug
> report was filed in the context of this discussion:
>
>   https://lists.gnu.org/archive/html/emacs-devel/2020-04/msg01386.html
>
> where I said that I think such UI effects should be implemented by
> using images, not special characters and special fonts.

Indeed. You're right about that. We should use dynamically-generated
image specs for them. That's what my patch allows for.

> > and enhancing image specs to handle such context-dependent
> > glyphs is wrong, because it moves code into the image backend that
> > applies to all image backends.
>
> "Image backend" in this context is the image libraries, like librsvg
> and libpng, is that right?

Yes.

> If so, which one of them can do the stuff
> Clément reported missing?

Err, who said they could? I'm saying they _shouldn't_. It's not the
image backend's job to alter and adapt an image, just to read a
compressed version of a bitmap and uncompress it, interpreting
whatever method of compression (say, vectorization) was chosen.

> > The enhancement I propose is a layer of indirection, allowing the
> > image spec itself to be adjusted to face/font properties.
>
> The kind of adjustments that we need for the use case which prompted
> this discussion can be done inside the display engine.

As opposed to doing them when the spec is evaluated?

> > And, no, there's no way for an image backend to interpret that. We
> > have to use different image specs.
>
> A Lisp program that prepares such display can prepare the spec
> accordingly, if needed.

That's what I'm proposing: call a Lisp program to prepare a spec
whenever we display the glyph. Not more often, which is wasteful.

Except you're currently wrong: a Lisp program cannot prepare "the
spec" accordingly, because there might be several required specs in
effect at the same time, for example.

> Any effects that cannot be explicitly
> produced by Lisp and we'd need the display code to produce can be
> communicated using the image spec keywords, like we always do.  For
> example, if we want the image to scale with the surrounding face, we
> can have a special value of the :scale attribute.  And similarly with
> other attributes; we can also invent new keywords for attributes
> currently not supported.

Yes, that describes what I'm doing, except for the important point
that the spec is generated per occurence of the glyph rather than once
globally.

> > "you want images, not character-like glyphs" isn't an argument, it's
> > simply a statement that you don't want my use case to be supported.
>
> It just means your use case is different from what is being discussed
> here, and serves purposes other than those which prompted this bug
> report.  I don't think we should mix them.

It's strict containment: my use case is more general.

> > > Within the context of what these icons are supposed to be used for, I
> > > envision the images coming with bright, catchy colors that should be
> > > left alone, not enhanced by color and contrast tweaking of whatever
> > > happens to be the face colors the user wants.
> >
> > I'm not sure which icons you're thinking about, but I certainly don't
> > want my symbols to have "bright, catchy colors that should be left
> > alone".
>
> I suggest to read the above discussion, and also look at the UI
> look-and-feel that is being sought.  You will see many examples there
> of the kind of images that people would like to see.  I think their
> vivid colors is one of the main aspects that attract users to such UI.

I did read the discussion, and the main thing mentioned about their
colors is that they shouldn't be fixed, i.e. not "left alone".

> > I'm still not sure whether you're suggesting anything that would
> > handle my use case even remotely, or simply saying it's not a use case
> > that Emacs should be extensible to.
>
> I guess I'm saying the latter.

My impression is you're treating extensibility itself as something to
be avoided, not as something on the benefit side of a cost-benefit
analysis (cost: 5 lines of actual code. benefit: solves both the more
specific use case sought here and the more general use case I need).

> Maybe if you explained when such use
> cases arise, I will agree with you.  But in any case, it's a different
> use case.

A more general one.

As to how they arise: mathematicians, for example, have a
long-standing tradition of making up symbols. Those new symbols aren't
(and shouldn't be) in Unicode, and there are many other symbols that,
for example, cannot be in Unicode for legal or ethical reasons. Users
should be able to display such symbols in an Emacs buffer and have
them be as close to character glyphs (or different from them) as they
are willing to make them.

I remain convinced that I'm not smart enough to figure out in advance
the precise set of use cases I want a feature for. You shouldn't limit
generality to handle only those cases you're convinced are useful.





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-04-25 17:46           ` Alan Third
  2020-04-25 18:07             ` Pip Cet
@ 2020-04-26 21:17             ` Alan Third
  2020-04-26 22:48               ` Clément Pit-Claudel
  2020-04-27  2:27               ` Eli Zaretskii
  1 sibling, 2 replies; 52+ messages in thread
From: Alan Third @ 2020-04-26 21:17 UTC (permalink / raw)
  To: Clément Pit-Claudel, Eli Zaretskii, 40845, pipcet

On Sat, Apr 25, 2020 at 06:46:51PM +0100, Alan Third wrote:
> On Sat, Apr 25, 2020 at 01:24:13PM -0400, Clément Pit-Claudel wrote:
> > On 25/04/2020 13.02, Eli Zaretskii wrote:
> > > IMO the foreground of an image shouldn't be affected by the
> > > current face's foreground.  Images should come with their own colors,
> > > and be displayed like that.  I think in the context of the discussion
> > > that led to this bug report it's actually almost a must: we want
> > > images with attractive colors to serve as the icons, we don't want
> > > them to be affected by whatever face happens to be nearby.
> > 
> > Yes, of course: if an image has a foreground color, it should be
> > respected. But it's not uncommon for SVG images to not include a
> > foreground color, as shown in the repro. In that case, the image
> > should use the current foreground color, I think. (of course, a
> > :foreground keyword, if any, should take precedence; that is issue
> > 4).
> 
> Lars fixed the foreground issue for eww by wrapping svg files in
> another svg. See svg--wrap-svg in shr.el (bug#37159).
> 
> I think this is the only practical way to handle svg files with no
> foreground colour set. To do this when loading _any_ svg we’d probably
> have to move it into create-image or image.c.

FWIW, with some experimentation I’ve found that this wrapping method
can easily sort the scaling problems too.

The process would have to go, roughly:

 * load the svg code
 * parse it with librsvg
 * extract the size
 * calculate the new size (compute_image_size in image.c should work
   fine)
 * base64 encode the original svg
 * wrap it in the new svg code
 * parse
 * produce the bitmap

Then we’re probably as well skipping all the matrix calculation stuff,
the same as we do for ImageMagick, as the bitmap should be the exact
size we want.

I’m happy to give this a go, but I’m not sure about base64 encoding.
Do we already have a way of doing that to a char buffer?
-- 
Alan Third





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-04-26 21:17             ` Alan Third
@ 2020-04-26 22:48               ` Clément Pit-Claudel
  2020-04-27 15:22                 ` Alan Third
  2020-05-03 14:13                 ` Alan Third
  2020-04-27  2:27               ` Eli Zaretskii
  1 sibling, 2 replies; 52+ messages in thread
From: Clément Pit-Claudel @ 2020-04-26 22:48 UTC (permalink / raw)
  To: Alan Third, Eli Zaretskii, 40845, pipcet

On 26/04/2020 17.17, Alan Third wrote:
> I’m happy to give this a go, but I’m not sure about base64 encoding.
> Do we already have a way of doing that to a char buffer?

We have base64-encode-region and base64-encode-string, which are both C functions — but why do we need to base64 encode?





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-04-26 21:17             ` Alan Third
  2020-04-26 22:48               ` Clément Pit-Claudel
@ 2020-04-27  2:27               ` Eli Zaretskii
  1 sibling, 0 replies; 52+ messages in thread
From: Eli Zaretskii @ 2020-04-27  2:27 UTC (permalink / raw)
  To: Alan Third; +Cc: cpitclaudel, 40845, pipcet

> Date: Sun, 26 Apr 2020 22:17:41 +0100
> From: Alan Third <alan@idiocy.org>
> 
> I’m happy to give this a go, but I’m not sure about base64 encoding.
> Do we already have a way of doing that to a char buffer?

I don't think I understand the question.  Can you elaborate?





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-04-26 22:48               ` Clément Pit-Claudel
@ 2020-04-27 15:22                 ` Alan Third
  2020-04-27 16:04                   ` Clément Pit-Claudel
  2020-05-03 14:13                 ` Alan Third
  1 sibling, 1 reply; 52+ messages in thread
From: Alan Third @ 2020-04-27 15:22 UTC (permalink / raw)
  To: Clément Pit-Claudel; +Cc: 40845, pipcet

On Sun, Apr 26, 2020 at 06:48:09PM -0400, Clément Pit-Claudel wrote:
> On 26/04/2020 17.17, Alan Third wrote:
> > I’m happy to give this a go, but I’m not sure about base64 encoding.
> > Do we already have a way of doing that to a char buffer?
> 
> We have base64-encode-region and base64-encode-string, which are
> both C functions — but why do we need to base64 encode?

I could be wrong, but in order to wrap the SVG file in another SVG, we
need to do something like:

    <svg xmlns:xlink="http://www.w3.org/1999/xlink"
         xmlns:xi="http://www.w3.org/2001/XInclude"
         width="100" height="100"
         preserveAspectRatio="none"
         viewBox="0 0 283.465 283.465">
      <xi:include href="data:image/svg+xml;base64,<base64 encoded data>">
      </xi:include>
    </svg>

We can’t just put the contents in directly, like:

    <svg xmlns:xlink="http://www.w3.org/1999/xlink"
         width="100" height="100"
         preserveAspectRatio="none"
         viewBox="0 0 283.465 283.465">
      <!-- file contents -->   
      <svg>
         stuff
      </svg>
      <!-- end file contents -->
    </svg>

as the file may (and probably should) have XML declarations at the
start which break the SVG file. We could strip them out but I’m not
sure that that’s better than base64 encoding, as it would mean
modifying the contents and I’m not sure that’s the only thing that
might cause problems.

We could also potentially just insert the file as‐is like so:

    <svg xmlns:xlink="http://www.w3.org/1999/xlink"
         xmlns:xi="http://www.w3.org/2001/XInclude"
         width="100" height="100"
         preserveAspectRatio="none"
         viewBox="0 0 283.465 283.465">
      <xi:include href="data:image/svg+xml;utf8,<svg>stuff</svg>">
      </xi:include>
    </svg>

but I can’t make that work. I think we’d have to URL encode the angle
brackets and any quotes.

If there’s anything obvious I’ve missed, please let me know.
-- 
Alan Third





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-04-26 19:00                     ` Pip Cet
@ 2020-04-27 15:47                       ` Eli Zaretskii
  0 siblings, 0 replies; 52+ messages in thread
From: Eli Zaretskii @ 2020-04-27 15:47 UTC (permalink / raw)
  To: Pip Cet; +Cc: cpitclaudel, 40845

> From: Pip Cet <pipcet@gmail.com>
> Date: Sun, 26 Apr 2020 19:00:36 +0000
> Cc: cpitclaudel@gmail.com, 40845@debbugs.gnu.org
> 
> > Then I guess we are talking about two different use cases.
> 
> A more general one, and a more limited and specific one. As it
> happens, the fix for the more general one is simpler.

"More general" in what sense?  Using Lisp does mean you could write
more general programs, but it doesn't necessarily mean you will be
able to solve more general problems.  The display code maintains a lot
of state that describes each position on the screen (see 'struct it'
in dispextern.h), and your proposal seems to expose only the font and
the face attributes to the Lisp function.  What about the other
information? are you suggesting to expose that as well?  For example,
some use cases may wish to know the pixel coordinates of the image
being rendered, or whether it's on a continued or an R2L line, or the
ascent or descent of the screen line, or the pixel distance from the
window edge, etc. etc.  The display code has all of that at its
fingertips.

> > > and enhancing image specs to handle such context-dependent
> > > glyphs is wrong, because it moves code into the image backend that
> > > applies to all image backends.
> >
> > "Image backend" in this context is the image libraries, like librsvg
> > and libpng, is that right?
> 
> Yes.

That's what I thought.  Then I don't think I understand your comment
about "moving code into the image backend", since I never proposed to
move anything into those libraries.  We need to force those of the
libraries that are capable to produce the images we want.  Like force
a certain background of an SVG image.  That is all done outside of the
backends.

> > A Lisp program that prepares such display can prepare the spec
> > accordingly, if needed.
> 
> That's what I'm proposing: call a Lisp program to prepare a spec
> whenever we display the glyph. Not more often, which is wasteful.

I meant a Lisp program that prepared the spec before redisplay was
entered.  There's no need to re-evaluate it each time the
corresponding part of the screen is updated or Emacs needs to
calculate its layout for other purposes, such as moving the cursor N
lines down on the screen.  Please consider how many times this code
will be executed, sometimes in contexts that are completely unrelated
to showing the images.

> Except you're currently wrong: a Lisp program cannot prepare "the
> spec" accordingly, because there might be several required specs in
> effect at the same time, for example.

We should identify the aspects of the images we'd like to control, and
enhance the image display to obey those aspects when needed.  This is
not complicated enough to call for a Lisp implementation, and doesn't
justify the downsides of calling Lisp from the display code.

> My impression is you're treating extensibility itself as something to
> be avoided, not as something on the benefit side of a cost-benefit
> analysis (cost: 5 lines of actual code. benefit: solves both the more
> specific use case sought here and the more general use case I need).

I indeed prefer to avoid extending the display engine in Lisp, as
explained elsewhere.  I hope I convinced you, or that at least you see
my point.  Other extensions of the display code are much more welcome,
although the resulting complexity should be carefully considered and
weighed against the advantages.  The display code is extremely complex
and handles an almost infinite number of use cases, so much so that it
sometimes takes years to find bugs in some subtle use case.  We should
try not to over-complicate the code without a good reason.  And a
theoretical "generalization" is not a good reason in my book.

> As to how they arise: mathematicians, for example, have a
> long-standing tradition of making up symbols. Those new symbols aren't
> (and shouldn't be) in Unicode, and there are many other symbols that,
> for example, cannot be in Unicode for legal or ethical reasons. Users
> should be able to display such symbols in an Emacs buffer and have
> them be as close to character glyphs (or different from them) as they
> are willing to make them.

Could you please show examples of such symbols, and tell how they are
displayed by other editors or word processors?

> I remain convinced that I'm not smart enough to figure out in advance
> the precise set of use cases I want a feature for. You shouldn't limit
> generality to handle only those cases you're convinced are useful.

I don't want to limit generality, I want to limit the price we pay for
a use case that has yet to materialize.  I think this keeps the Emacs
display code from becoming completely unmanageable.





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-04-27 15:22                 ` Alan Third
@ 2020-04-27 16:04                   ` Clément Pit-Claudel
  0 siblings, 0 replies; 52+ messages in thread
From: Clément Pit-Claudel @ 2020-04-27 16:04 UTC (permalink / raw)
  To: Alan Third, Eli Zaretskii, 40845, pipcet

On 27/04/2020 11.22, Alan Third wrote:
> On Sun, Apr 26, 2020 at 06:48:09PM -0400, Clément Pit-Claudel wrote:
>> On 26/04/2020 17.17, Alan Third wrote:
>>> I’m happy to give this a go, but I’m not sure about base64 encoding.
>>> Do we already have a way of doing that to a char buffer?
>>
>> We have base64-encode-region and base64-encode-string, which are
>> both C functions — but why do we need to base64 encode?
> 
> We can’t just put the contents in directly […]
> as the file may (and probably should) have XML declarations at the
> start which break the SVG file. We could strip them out but I’m not
> sure that that’s better than base64 encoding, as it would mean
> modifying the contents and I’m not sure that’s the only thing that
> might cause problems.

Excellent point, I hadn't considered the xml declaration at the top.






^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-04-26 22:48               ` Clément Pit-Claudel
  2020-04-27 15:22                 ` Alan Third
@ 2020-05-03 14:13                 ` Alan Third
  2020-05-03 14:18                   ` Lars Ingebrigtsen
  2020-05-03 16:07                   ` Eli Zaretskii
  1 sibling, 2 replies; 52+ messages in thread
From: Alan Third @ 2020-05-03 14:13 UTC (permalink / raw)
  To: Clément Pit-Claudel; +Cc: 40845, pipcet

On Sun, Apr 26, 2020 at 06:48:09PM -0400, Clément Pit-Claudel wrote:
> On 26/04/2020 17.17, Alan Third wrote:
> > I’m happy to give this a go, but I’m not sure about base64 encoding.
> > Do we already have a way of doing that to a char buffer?
> 
> We have base64-encode-region and base64-encode-string, which are both C functions — but why do we need to base64 encode?

I’ve run into a problem with the base64 encoding.

/usr/bin/base64 encodes this file differently from Emacs:

    https://upload.wikimedia.org/wikipedia/commons/9/92/MixedUnitAddition.svg

librsvg doesn’t like the way Emacs encodes the file, but is fine with
the system base64.

I think the problem is the GBP £ symbol on line 39.

Do I need to do something special, like set up character encodings?
-- 
Alan Third





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-05-03 14:13                 ` Alan Third
@ 2020-05-03 14:18                   ` Lars Ingebrigtsen
  2020-05-03 16:07                   ` Eli Zaretskii
  1 sibling, 0 replies; 52+ messages in thread
From: Lars Ingebrigtsen @ 2020-05-03 14:18 UTC (permalink / raw)
  To: Alan Third; +Cc: Clément Pit-Claudel, pipcet, 40845

Alan Third <alan@idiocy.org> writes:

> I’ve run into a problem with the base64 encoding.
>
> /usr/bin/base64 encodes this file differently from Emacs:
>
>     https://upload.wikimedia.org/wikipedia/commons/9/92/MixedUnitAddition.svg
>
> librsvg doesn’t like the way Emacs encodes the file, but is fine with
> the system base64.
>
> I think the problem is the GBP £ symbol on line 39.
>
> Do I need to do something special, like set up character encodings?

Before base64-encoding, you should encode the data to whatever coding
system is expected, which would probably be utf-8 here.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-05-03 14:13                 ` Alan Third
  2020-05-03 14:18                   ` Lars Ingebrigtsen
@ 2020-05-03 16:07                   ` Eli Zaretskii
  2020-05-03 16:24                     ` Alan Third
  1 sibling, 1 reply; 52+ messages in thread
From: Eli Zaretskii @ 2020-05-03 16:07 UTC (permalink / raw)
  To: Alan Third; +Cc: cpitclaudel, 40845, pipcet

> Date: Sun, 3 May 2020 15:13:48 +0100
> From: Alan Third <alan@idiocy.org>
> Cc: Eli Zaretskii <eliz@gnu.org>, 40845@debbugs.gnu.org, pipcet@gmail.com
> 
> I’ve run into a problem with the base64 encoding.
> 
> /usr/bin/base64 encodes this file differently from Emacs:
> 
>     https://upload.wikimedia.org/wikipedia/commons/9/92/MixedUnitAddition.svg
> 
> librsvg doesn’t like the way Emacs encodes the file, but is fine with
> the system base64.
> 
> I think the problem is the GBP £ symbol on line 39.
> 
> Do I need to do something special, like set up character encodings?

You need to make sure the text passed to base64-encode-region is
unibyte.  I suggest to look at how other packages call that function.

Let me know if this general advice doesn't help.

Thanks.





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-05-03 16:07                   ` Eli Zaretskii
@ 2020-05-03 16:24                     ` Alan Third
  2020-05-03 16:49                       ` Eli Zaretskii
  2020-05-09 14:27                       ` Alan Third
  0 siblings, 2 replies; 52+ messages in thread
From: Alan Third @ 2020-05-03 16:24 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: cpitclaudel, 40845, pipcet

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

On Sun, May 03, 2020 at 07:07:56PM +0300, Eli Zaretskii wrote:
> > Date: Sun, 3 May 2020 15:13:48 +0100
> > From: Alan Third <alan@idiocy.org>
> > Cc: Eli Zaretskii <eliz@gnu.org>, 40845@debbugs.gnu.org, pipcet@gmail.com
> > 
> > I’ve run into a problem with the base64 encoding.
> > 
> > /usr/bin/base64 encodes this file differently from Emacs:
> > 
> >     https://upload.wikimedia.org/wikipedia/commons/9/92/MixedUnitAddition.svg
> > 
> > librsvg doesn’t like the way Emacs encodes the file, but is fine with
> > the system base64.
> > 
> > I think the problem is the GBP £ symbol on line 39.
> > 
> > Do I need to do something special, like set up character encodings?
> 
> You need to make sure the text passed to base64-encode-region is
> unibyte.  I suggest to look at how other packages call that function.
> 
> Let me know if this general advice doesn't help.

Yes, it’s sorted the problem. Thanks!

I’ve attached a first pass. It solves 1 and 4 from the original bug
report: scaling and setting the foreground colour.

One thing is that it gets the foreground colour from the default face
instead of the current face. I’m not sure how to solve that.

I’m unsure if my use of malloc is OK, as I know Emacs code uses some
different methods in different places.

-- 
Alan Third

[-- Attachment #2: 0001-Set-basic-SVG-attributes-bug-40845.patch --]
[-- Type: text/plain, Size: 10906 bytes --]

From 78026c9697edda23073409a59176367fc1ad58ba Mon Sep 17 00:00:00 2001
From: Alan Third <alan@idiocy.org>
Date: Sun, 3 May 2020 17:09:31 +0100
Subject: [PATCH] Set basic SVG attributes (bug#40845)

* lisp/net/shr.el (shr-parse-image-data): Remove call to
svg--wrap-svg.
(svg--wrap-svg): Remove function.
* src/image.c (image_set_transform): SVGs should not be scaled by
native transforms as they should be the correct size already.
(enum svg_keyword_index):
(svg_format): Add the :foreground keyword.
(svg_load_image): Calculate the desired size of the SVG and wrap it
in another SVG that allows us to resize it.  Also set the background
and foreground colors.
---
 lisp/net/shr.el |  17 ------
 src/image.c     | 150 +++++++++++++++++++++++++++++++++++++++---------
 2 files changed, 122 insertions(+), 45 deletions(-)

diff --git a/lisp/net/shr.el b/lisp/net/shr.el
index 1f80ab74db..c862cf04e3 100644
--- a/lisp/net/shr.el
+++ b/lisp/net/shr.el
@@ -1195,25 +1195,8 @@ shr-parse-image-data
             ;; that are non-ASCII.
 	    (shr-dom-to-xml
 	     (libxml-parse-xml-region (point) (point-max)) 'utf-8)))
-    ;; SVG images often do not have a specified foreground/background
-    ;; color, so wrap them in styles.
-    (when (and (display-images-p)
-               (eq content-type 'image/svg+xml))
-      (setq data (svg--wrap-svg data)))
     (list data content-type)))
 
-(defun svg--wrap-svg (data)
-  "Add a default foreground colour to SVG images."
-  (let ((size (image-size (create-image data nil t :scaling 1) t)))
-    (with-temp-buffer
-      (insert
-       (format
-        "<svg xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:xi=\"http://www.w3.org/2001/XInclude\" style=\"color: %s;\" viewBox=\"0 0 %d %d\"> <xi:include href=\"data:image/svg+xml;base64,%s\"></xi:include></svg>"
-        (face-foreground 'default)
-        (car size) (cdr size)
-        (base64-encode-string data t)))
-      (buffer-string))))
-
 (defun shr-image-displayer (content-function)
   "Return a function to display an image.
 CONTENT-FUNCTION is a function to retrieve an image for a cid url that
diff --git a/src/image.c b/src/image.c
index c8a192aaaf..06760a62c2 100644
--- a/src/image.c
+++ b/src/image.c
@@ -2108,7 +2108,17 @@ image_set_transform (struct frame *f, struct image *img)
 
   /* Determine size.  */
   int width, height;
-  compute_image_size (img->width, img->height, img->spec, &width, &height);
+
+#ifdef HAVE_RSVG
+  /* SVGs are pre-scaled to the correct size.  */
+  if (EQ (image_spec_value (img->spec, QCtype, NULL), Qsvg))
+    {
+      width = img->width;
+      height = img->height;
+    }
+  else
+#endif
+    compute_image_size (img->width, img->height, img->spec, &width, &height);
 
   /* Determine rotation.  */
   double rotation = 0.0;
@@ -9393,6 +9403,7 @@ DEFUN ("imagemagick-types", Fimagemagick_types, Simagemagick_types, 0, 0, 0,
   SVG_ALGORITHM,
   SVG_HEURISTIC_MASK,
   SVG_MASK,
+  SVG_FOREGROUND,
   SVG_BACKGROUND,
   SVG_LAST
 };
@@ -9411,6 +9422,7 @@ DEFUN ("imagemagick-types", Fimagemagick_types, Simagemagick_types, 0, 0, 0,
   {":conversion",	IMAGE_DONT_CHECK_VALUE_TYPE,		0},
   {":heuristic-mask",	IMAGE_DONT_CHECK_VALUE_TYPE,		0},
   {":mask",		IMAGE_DONT_CHECK_VALUE_TYPE,		0},
+  {":foreground",	IMAGE_STRING_OR_NIL_VALUE,		0},
   {":background",	IMAGE_STRING_OR_NIL_VALUE,		0}
 };
 
@@ -9675,6 +9687,8 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
   int height;
   const guint8 *pixels;
   int rowstride;
+  char *wrapped_contents;
+  ptrdiff_t wrapped_size;
 
 #if ! GLIB_CHECK_VERSION (2, 36, 0)
   /* g_type_init is a glib function that must be called prior to
@@ -9682,6 +9696,8 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
   g_type_init ();
 #endif
 
+  /* Parse the unmodified SVG data so we can get it's initial size.  */
+
 #if LIBRSVG_CHECK_VERSION (2, 32, 0)
   GInputStream *input_stream
     = g_memory_input_stream_new_from_data (contents, size, NULL);
@@ -9710,6 +9726,107 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
   rsvg_handle_write (rsvg_handle, (unsigned char *) contents, size, &err);
   if (err) goto rsvg_error;
 
+  /* The parsing is complete, rsvg_handle is ready to used, close it
+     for further writes.  */
+  rsvg_handle_close (rsvg_handle, &err);
+  if (err) goto rsvg_error;
+#endif
+
+  /* Get the image dimensions.  */
+  rsvg_handle_get_dimensions (rsvg_handle, &dimension_data);
+
+  /* We are now done with the unmodified data.  */
+  g_object_unref (rsvg_handle);
+
+  /* Calculate the final image size.  */
+  compute_image_size (dimension_data.width, dimension_data.height,
+                      img->spec, &width, &height);
+
+  /* Wrap the SVG data in another SVG.  This allows us to set the
+     width and height, as well as modify the foreground and background
+     colors.  */
+  {
+    Lisp_Object value;
+    unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
+    unsigned long background = FRAME_BACKGROUND_PIXEL (f);
+
+    Lisp_Object encoded_contents = Fbase64_encode_string
+      (make_unibyte_string (contents, size), Qt);
+
+    /* The wrapper sets the foreground color, width and height, and
+       viewBox must contain the dimensions of the original image.  It
+       also draws a rectangle over the whole space, set to the
+       background color, before including the original image. This
+       acts to set the background color, instead of leaving it
+       transparent.  */
+    const char *wrapper =
+      "<svg xmlns:xlink=\"http://www.w3.org/1999/xlink\" "
+      "xmlns:xi=\"http://www.w3.org/2001/XInclude\" "
+      "style=\"color: #%06X; fill: currentColor;\" "
+      "width=\"%d\" height=\"%d\" preserveAspectRatio=\"none\" "
+      "viewBox=\"0 0 %d %d\">"
+      "<rect width=\"100%%\" height=\"100%%\" fill=\"#%06X\"/>"
+      "<xi:include href=\"data:image/svg+xml;base64,%s\"></xi:include>"
+      "</svg>";
+
+    /* FIXME: I've added 64 in the hope it will cover the size of the
+       width and height strings and things.  */
+    int buffer_size = SBYTES (encoded_contents) + strlen (wrapper) + 64;
+
+    value = image_spec_value (img->spec, QCforeground, NULL);
+    if (!NILP (value))
+      {
+        foreground = image_alloc_image_color (f, img, value, foreground);
+      }
+    value = image_spec_value (img->spec, QCbackground, NULL);
+    if (!NILP (value))
+      {
+        background = image_alloc_image_color (f, img, value, background);
+        img->background = background;
+        img->background_valid = 1;
+      }
+
+    wrapped_contents = malloc (buffer_size);
+
+    if (!wrapped_contents
+        || buffer_size <= snprintf (wrapped_contents, buffer_size, wrapper,
+                                    foreground & 0xFFFFFF, width, height,
+                                    dimension_data.width, dimension_data.height,
+                                    background & 0xFFFFFF, SSDATA (encoded_contents)))
+      goto rsvg_error;
+
+    wrapped_size = strlen (wrapped_contents);
+  }
+
+  /* Now we parse the wrapped version.  */
+
+#if LIBRSVG_CHECK_VERSION (2, 32, 0)
+  input_stream = g_memory_input_stream_new_from_data (wrapped_contents, wrapped_size, NULL);
+  base_file = filename ? g_file_new_for_path (filename) : NULL;
+  rsvg_handle = rsvg_handle_new_from_stream_sync (input_stream, base_file,
+						  RSVG_HANDLE_FLAGS_NONE,
+						  NULL, &err);
+  if (base_file)
+    g_object_unref (base_file);
+  g_object_unref (input_stream);
+
+  /* Check rsvg_handle too, to avoid librsvg 2.40.13 bug (Bug#36773#26).  */
+  if (!rsvg_handle || err) goto rsvg_error;
+#else
+  /* Make a handle to a new rsvg object.  */
+  rsvg_handle = rsvg_handle_new ();
+  eassume (rsvg_handle);
+
+  /* Set base_uri for properly handling referenced images (via 'href').
+     See rsvg bug 596114 - "image refs are relative to curdir, not .svg file"
+     <https://gitlab.gnome.org/GNOME/librsvg/issues/33>. */
+  if (filename)
+    rsvg_handle_set_base_uri (rsvg_handle, filename);
+
+  /* Parse the contents argument and fill in the rsvg_handle.  */
+  rsvg_handle_write (rsvg_handle, (unsigned char *) wrapped_contents, wrapped_size, &err);
+  if (err) goto rsvg_error;
+
   /* The parsing is complete, rsvg_handle is ready to used, close it
      for further writes.  */
   rsvg_handle_close (rsvg_handle, &err);
@@ -9728,6 +9845,7 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
   pixbuf = rsvg_handle_get_pixbuf (rsvg_handle);
   if (!pixbuf) goto rsvg_error;
   g_object_unref (rsvg_handle);
+  free (wrapped_contents);
 
   /* Extract some meta data from the svg handle.  */
   width     = gdk_pixbuf_get_width (pixbuf);
@@ -9752,25 +9870,6 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
 
     init_color_table ();
 
-    /* Handle alpha channel by combining the image with a background
-       color.  */
-    Emacs_Color background;
-    Lisp_Object specified_bg = image_spec_value (img->spec, QCbackground, NULL);
-    if (!STRINGP (specified_bg)
-	|| !FRAME_TERMINAL (f)->defined_color_hook (f,
-                                                    SSDATA (specified_bg),
-                                                    &background,
-                                                    false,
-                                                    false))
-      FRAME_TERMINAL (f)->query_frame_background_color (f, &background);
-
-    /* SVG pixmaps specify transparency in the last byte, so right
-       shift 8 bits to get rid of it, since emacs doesn't support
-       transparency.  */
-    background.red   >>= 8;
-    background.green >>= 8;
-    background.blue  >>= 8;
-
     /* This loop handles opacity values, since Emacs assumes
        non-transparent images.  Each pixel must be "flattened" by
        calculating the resulting color, given the transparency of the
@@ -9784,14 +9883,7 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
 	    int blue    = *pixels++;
 	    int 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)));
-
-	    PUT_PIXEL (ximg, x, y, lookup_rgb_color (f, red, green, blue));
+	    PUT_PIXEL (ximg, x, y, lookup_rgb_color (f, red << 8, green << 8, blue << 8));
 	  }
 
 	pixels += rowstride - 4 * width;
@@ -9821,6 +9913,8 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
  rsvg_error:
   if (rsvg_handle)
     g_object_unref (rsvg_handle);
+  if (wrapped_contents)
+    free (wrapped_contents);
   /* 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.26.1


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-05-03 16:24                     ` Alan Third
@ 2020-05-03 16:49                       ` Eli Zaretskii
  2020-05-03 18:38                         ` Alan Third
  2020-05-09 14:27                       ` Alan Third
  1 sibling, 1 reply; 52+ messages in thread
From: Eli Zaretskii @ 2020-05-03 16:49 UTC (permalink / raw)
  To: Alan Third; +Cc: cpitclaudel, 40845, pipcet

> Date: Sun, 3 May 2020 17:24:17 +0100
> From: Alan Third <alan@idiocy.org>
> Cc: cpitclaudel@gmail.com, 40845@debbugs.gnu.org, pipcet@gmail.com
> 
> I’ve attached a first pass. It solves 1 and 4 from the original bug
> report: scaling and setting the foreground colour.

Thanks.

> One thing is that it gets the foreground colour from the default face
> instead of the current face. I’m not sure how to solve that.

Can you describe the difficulty in using the current face?

> I’m unsure if my use of malloc is OK, as I know Emacs code uses some
> different methods in different places.

It's okay to call malloc and free in image.c.





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-05-03 16:49                       ` Eli Zaretskii
@ 2020-05-03 18:38                         ` Alan Third
  2020-05-03 19:17                           ` Eli Zaretskii
  0 siblings, 1 reply; 52+ messages in thread
From: Alan Third @ 2020-05-03 18:38 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: cpitclaudel, 40845, pipcet

On Sun, May 03, 2020 at 07:49:45PM +0300, Eli Zaretskii wrote:
> > Date: Sun, 3 May 2020 17:24:17 +0100
> > From: Alan Third <alan@idiocy.org>
> > Cc: cpitclaudel@gmail.com, 40845@debbugs.gnu.org, pipcet@gmail.com
> > 
> > One thing is that it gets the foreground colour from the default face
> > instead of the current face. I’m not sure how to solve that.
> 
> Can you describe the difficulty in using the current face?

I’m mostly unsure how I access it. I don’t think images or image.c
have any real concept of where they are in the buffer.

I think we’d also have to recreate the image any time the face
changed. For example in Clement’s test code from the original bug
report, he has the face changing when the mouse hovers over the text.
In order to handle that case we would need to create a new version of
the image with the updated foreground and background when the mouse
moves over it.

We can work around having to update the background by using proper
transparency, but I don’t know what other problems that might
introduce. It’s harder for the foreground. Pip Cet suggested creating
masks for foreground and background and using them to draw the image
in sections, but I feel that’s perhaps getting a little complex,
especially when I think most images won’t be changing their foreground
and background colours.

I feel it would be easier just to have two or more cached images with
different foreground and backgrounds as required.

> > I’m unsure if my use of malloc is OK, as I know Emacs code uses some
> > different methods in different places.
> 
> It's okay to call malloc and free in image.c.

Excellent, thanks.
-- 
Alan Third





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-05-03 18:38                         ` Alan Third
@ 2020-05-03 19:17                           ` Eli Zaretskii
  0 siblings, 0 replies; 52+ messages in thread
From: Eli Zaretskii @ 2020-05-03 19:17 UTC (permalink / raw)
  To: Alan Third; +Cc: cpitclaudel, 40845, pipcet

> Date: Sun, 3 May 2020 19:38:39 +0100
> From: Alan Third <alan@idiocy.org>
> Cc: cpitclaudel@gmail.com, 40845@debbugs.gnu.org, pipcet@gmail.com
> 
> > > One thing is that it gets the foreground colour from the default face
> > > instead of the current face. I’m not sure how to solve that.
> > 
> > Can you describe the difficulty in using the current face?
> 
> I’m mostly unsure how I access it. I don’t think images or image.c
> have any real concept of where they are in the buffer.

When the 'load' method (in your case, svg_load) is called from
prepare_image_for_display, we have the face information handy.
Usually, at that point we don't call the 'load' method, because the
image is already loaded and cached.  But we could change the logic if
we know that the image must be modified to have a different face.
Then we can pass the color information to the 'load' method.

> I think we’d also have to recreate the image any time the face
> changed.

Yes, because changing the color(s) makes a different image.  But that
is not a problem, I think.

> I feel it would be easier just to have two or more cached images with
> different foreground and backgrounds as required.

Agreed.  At least as the first approximation; we could always change
that later if we find this not to be good enough.





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-05-03 16:24                     ` Alan Third
  2020-05-03 16:49                       ` Eli Zaretskii
@ 2020-05-09 14:27                       ` Alan Third
  2020-05-09 19:54                         ` Alan Third
  1 sibling, 1 reply; 52+ messages in thread
From: Alan Third @ 2020-05-09 14:27 UTC (permalink / raw)
  To: Eli Zaretskii, cpitclaudel, 40845, pipcet

On Sun, May 03, 2020 at 05:24:17PM +0100, Alan Third wrote:
> 
> I’ve attached a first pass. It solves 1 and 4 from the original bug
> report: scaling and setting the foreground colour.

Can someone please try the patch from the previous email on a non‐NS
platform and confirm whether or not the background colour in the image
matches the background colour of the text?

They don’t match here, but I strongly suspect that’s because the NS
port uses different colour spaces for images and everything else.
-- 
Alan Third





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-05-09 14:27                       ` Alan Third
@ 2020-05-09 19:54                         ` Alan Third
  2020-05-15 11:09                           ` Eli Zaretskii
  0 siblings, 1 reply; 52+ messages in thread
From: Alan Third @ 2020-05-09 19:54 UTC (permalink / raw)
  To: Eli Zaretskii, cpitclaudel, 40845, pipcet

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

On Sat, May 09, 2020 at 03:27:27PM +0100, Alan Third wrote:
> On Sun, May 03, 2020 at 05:24:17PM +0100, Alan Third wrote:
> > 
> > I’ve attached a first pass. It solves 1 and 4 from the original bug
> > report: scaling and setting the foreground colour.
> 
> Can someone please try the patch from the previous email on a non‐NS
> platform and confirm whether or not the background colour in the image
> matches the background colour of the text?
> 
> They don’t match here, but I strongly suspect that’s because the NS
> port uses different colour spaces for images and everything else.

Apologies, please can someone try the attached patch.
-- 
Alan Third

[-- Attachment #2: 0001-Set-basic-SVG-attributes-bug-40845.patch --]
[-- Type: text/plain, Size: 17527 bytes --]

From 6c1620ebd80bcfa1065b02350dfa875bec04fc0c Mon Sep 17 00:00:00 2001
From: Alan Third <alan@idiocy.org>
Date: Sun, 3 May 2020 17:09:31 +0100
Subject: [PATCH] Set basic SVG attributes (bug#40845)

---
 lisp/net/shr.el  |  17 -----
 src/dispextern.h |   2 +-
 src/gtkutil.c    |   2 +-
 src/image.c      | 179 ++++++++++++++++++++++++++++++++++++-----------
 src/nsmenu.m     |   2 +-
 src/xdisp.c      |   6 +-
 6 files changed, 145 insertions(+), 63 deletions(-)

diff --git a/lisp/net/shr.el b/lisp/net/shr.el
index 1f80ab74db..c862cf04e3 100644
--- a/lisp/net/shr.el
+++ b/lisp/net/shr.el
@@ -1195,25 +1195,8 @@ shr-parse-image-data
             ;; that are non-ASCII.
 	    (shr-dom-to-xml
 	     (libxml-parse-xml-region (point) (point-max)) 'utf-8)))
-    ;; SVG images often do not have a specified foreground/background
-    ;; color, so wrap them in styles.
-    (when (and (display-images-p)
-               (eq content-type 'image/svg+xml))
-      (setq data (svg--wrap-svg data)))
     (list data content-type)))
 
-(defun svg--wrap-svg (data)
-  "Add a default foreground colour to SVG images."
-  (let ((size (image-size (create-image data nil t :scaling 1) t)))
-    (with-temp-buffer
-      (insert
-       (format
-        "<svg xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:xi=\"http://www.w3.org/2001/XInclude\" style=\"color: %s;\" viewBox=\"0 0 %d %d\"> <xi:include href=\"data:image/svg+xml;base64,%s\"></xi:include></svg>"
-        (face-foreground 'default)
-        (car size) (cdr size)
-        (base64-encode-string data t)))
-      (buffer-string))))
-
 (defun shr-image-displayer (content-function)
   "Return a function to display an image.
 CONTENT-FUNCTION is a function to retrieve an image for a cid url that
diff --git a/src/dispextern.h b/src/dispextern.h
index 0b1f3d14ae..cd09e0846c 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -3475,7 +3475,7 @@ #define TRY_WINDOW_IGNORE_FONTS_CHANGE	(1 << 1)
 void mark_image_cache (struct image_cache *);
 bool valid_image_p (Lisp_Object);
 void prepare_image_for_display (struct frame *, struct image *);
-ptrdiff_t lookup_image (struct frame *, Lisp_Object);
+ptrdiff_t lookup_image (struct frame *, Lisp_Object, int face_id);
 
 #if defined HAVE_X_WINDOWS || defined USE_CAIRO || defined HAVE_NS
 #define RGB_PIXEL_COLOR unsigned long
diff --git a/src/gtkutil.c b/src/gtkutil.c
index 681f86f51b..2f6b664d2d 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -5101,7 +5101,7 @@ update_frame_tool_bar (struct frame *f)
           else
             idx = -1;
 
-          img_id = lookup_image (f, image);
+          img_id = lookup_image (f, image, -1);
           img = IMAGE_FROM_ID (f, img_id);
           prepare_image_for_display (f, img);
 
diff --git a/src/image.c b/src/image.c
index c8a192aaaf..5333d66c7d 100644
--- a/src/image.c
+++ b/src/image.c
@@ -1066,7 +1066,7 @@ DEFUN ("image-size", Fimage_size, Simage_size, 1, 3, 0,
   if (valid_image_p (spec))
     {
       struct frame *f = decode_window_system_frame (frame);
-      ptrdiff_t id = lookup_image (f, spec);
+      ptrdiff_t id = lookup_image (f, spec, -1);
       struct image *img = IMAGE_FROM_ID (f, id);
       int width = img->width + 2 * img->hmargin;
       int height = img->height + 2 * img->vmargin;
@@ -1096,7 +1096,7 @@ DEFUN ("image-mask-p", Fimage_mask_p, Simage_mask_p, 1, 2, 0,
   if (valid_image_p (spec))
     {
       struct frame *f = decode_window_system_frame (frame);
-      ptrdiff_t id = lookup_image (f, spec);
+      ptrdiff_t id = lookup_image (f, spec, -1);
       struct image *img = IMAGE_FROM_ID (f, id);
       if (img->mask)
 	mask = Qt;
@@ -1119,7 +1119,7 @@ DEFUN ("image-metadata", Fimage_metadata, Simage_metadata, 1, 2, 0,
   if (valid_image_p (spec))
     {
       struct frame *f = decode_window_system_frame (frame);
-      ptrdiff_t id = lookup_image (f, spec);
+      ptrdiff_t id = lookup_image (f, spec, -1);
       struct image *img = IMAGE_FROM_ID (f, id);
       ext = img->lisp_data;
     }
@@ -1586,7 +1586,8 @@ make_image_cache (void)
 /* Find an image matching SPEC in the cache, and return it.  If no
    image is found, return NULL.  */
 static struct image *
-search_image_cache (struct frame *f, Lisp_Object spec, EMACS_UINT hash)
+search_image_cache (struct frame *f, Lisp_Object spec, EMACS_UINT hash,
+                    unsigned long foreground, unsigned long background)
 {
   struct image *img;
   struct image_cache *c = FRAME_IMAGE_CACHE (f);
@@ -1609,8 +1610,8 @@ search_image_cache (struct frame *f, Lisp_Object spec, EMACS_UINT hash)
   for (img = c->buckets[i]; img; img = img->next)
     if (img->hash == hash
 	&& !NILP (Fequal (img->spec, spec))
-	&& img->frame_foreground == FRAME_FOREGROUND_PIXEL (f)
-	&& img->frame_background == FRAME_BACKGROUND_PIXEL (f))
+	&& img->frame_foreground == foreground
+	&& img->frame_background == background)
       break;
   return img;
 }
@@ -1621,7 +1622,7 @@ search_image_cache (struct frame *f, Lisp_Object spec, EMACS_UINT hash)
 static void
 uncache_image (struct frame *f, Lisp_Object spec)
 {
-  struct image *img = search_image_cache (f, spec, sxhash (spec));
+  struct image *img = search_image_cache (f, spec, sxhash (spec), FRAME_FOREGROUND_PIXEL (f), FRAME_BACKGROUND_PIXEL (f));
   if (img)
     {
       free_image (f, img);
@@ -2108,7 +2109,17 @@ image_set_transform (struct frame *f, struct image *img)
 
   /* Determine size.  */
   int width, height;
-  compute_image_size (img->width, img->height, img->spec, &width, &height);
+
+#ifdef HAVE_RSVG
+  /* SVGs are pre-scaled to the correct size.  */
+  if (EQ (image_spec_value (img->spec, QCtype, NULL), Qsvg))
+    {
+      width = img->width;
+      height = img->height;
+    }
+  else
+#endif
+    compute_image_size (img->width, img->height, img->spec, &width, &height);
 
   /* Determine rotation.  */
   double rotation = 0.0;
@@ -2275,11 +2286,15 @@ image_set_transform (struct frame *f, struct image *img)
    SPEC must be a valid Lisp image specification (see valid_image_p).  */
 
 ptrdiff_t
-lookup_image (struct frame *f, Lisp_Object spec)
+lookup_image (struct frame *f, Lisp_Object spec, int face_id)
 {
   struct image *img;
   EMACS_UINT hash;
 
+  struct face *face = (face_id >= 0) ? FACE_FROM_ID (f, face_id) : FRAME_DEFAULT_FACE (f);
+  unsigned long foreground = FACE_COLOR_TO_PIXEL (face->foreground, f);
+  unsigned long background = FACE_COLOR_TO_PIXEL (face->background, f);
+
   /* F must be a window-system frame, and SPEC must be a valid image
      specification.  */
   eassert (FRAME_WINDOW_P (f));
@@ -2287,7 +2302,7 @@ lookup_image (struct frame *f, Lisp_Object spec)
 
   /* Look up SPEC in the hash table of the image cache.  */
   hash = sxhash (spec);
-  img = search_image_cache (f, spec, hash);
+  img = search_image_cache (f, spec, hash, foreground, background);
   if (img && img->load_failed_p)
     {
       free_image (f, img);
@@ -2300,9 +2315,9 @@ lookup_image (struct frame *f, Lisp_Object spec)
       block_input ();
       img = make_image (spec, hash);
       cache_image (f, img);
+      img->frame_foreground = foreground;
+      img->frame_background = background;
       img->load_failed_p = ! img->type->load (f, img);
-      img->frame_foreground = FRAME_FOREGROUND_PIXEL (f);
-      img->frame_background = FRAME_BACKGROUND_PIXEL (f);
 
       /* If we can't load the image, and we don't have a width and
 	 height, use some arbitrary width and height so that we can
@@ -9393,6 +9408,7 @@ DEFUN ("imagemagick-types", Fimagemagick_types, Simagemagick_types, 0, 0, 0,
   SVG_ALGORITHM,
   SVG_HEURISTIC_MASK,
   SVG_MASK,
+  SVG_FOREGROUND,
   SVG_BACKGROUND,
   SVG_LAST
 };
@@ -9411,6 +9427,7 @@ DEFUN ("imagemagick-types", Fimagemagick_types, Simagemagick_types, 0, 0, 0,
   {":conversion",	IMAGE_DONT_CHECK_VALUE_TYPE,		0},
   {":heuristic-mask",	IMAGE_DONT_CHECK_VALUE_TYPE,		0},
   {":mask",		IMAGE_DONT_CHECK_VALUE_TYPE,		0},
+  {":foreground",	IMAGE_STRING_OR_NIL_VALUE,		0},
   {":background",	IMAGE_STRING_OR_NIL_VALUE,		0}
 };
 
@@ -9675,6 +9692,8 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
   int height;
   const guint8 *pixels;
   int rowstride;
+  char *wrapped_contents;
+  ptrdiff_t wrapped_size;
 
 #if ! GLIB_CHECK_VERSION (2, 36, 0)
   /* g_type_init is a glib function that must be called prior to
@@ -9682,6 +9701,8 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
   g_type_init ();
 #endif
 
+  /* Parse the unmodified SVG data so we can get it's initial size.  */
+
 #if LIBRSVG_CHECK_VERSION (2, 32, 0)
   GInputStream *input_stream
     = g_memory_input_stream_new_from_data (contents, size, NULL);
@@ -9710,6 +9731,107 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
   rsvg_handle_write (rsvg_handle, (unsigned char *) contents, size, &err);
   if (err) goto rsvg_error;
 
+  /* The parsing is complete, rsvg_handle is ready to used, close it
+     for further writes.  */
+  rsvg_handle_close (rsvg_handle, &err);
+  if (err) goto rsvg_error;
+#endif
+
+  /* Get the image dimensions.  */
+  rsvg_handle_get_dimensions (rsvg_handle, &dimension_data);
+
+  /* We are now done with the unmodified data.  */
+  g_object_unref (rsvg_handle);
+
+  /* Calculate the final image size.  */
+  compute_image_size (dimension_data.width, dimension_data.height,
+                      img->spec, &width, &height);
+
+  /* Wrap the SVG data in another SVG.  This allows us to set the
+     width and height, as well as modify the foreground and background
+     colors.  */
+  {
+    Lisp_Object value;
+    unsigned long foreground = img->frame_foreground;
+    unsigned long background = img->frame_background;
+
+    Lisp_Object encoded_contents = Fbase64_encode_string
+      (make_unibyte_string (contents, size), Qt);
+
+    /* The wrapper sets the foreground color, width and height, and
+       viewBox must contain the dimensions of the original image.  It
+       also draws a rectangle over the whole space, set to the
+       background color, before including the original image. This
+       acts to set the background color, instead of leaving it
+       transparent.  */
+    const char *wrapper =
+      "<svg xmlns:xlink=\"http://www.w3.org/1999/xlink\" "
+      "xmlns:xi=\"http://www.w3.org/2001/XInclude\" "
+      "style=\"color: #%06X; fill: currentColor;\" "
+      "width=\"%d\" height=\"%d\" preserveAspectRatio=\"none\" "
+      "viewBox=\"0 0 %d %d\">"
+      "<rect width=\"100%%\" height=\"100%%\" fill=\"#%06X\"/>"
+      "<xi:include href=\"data:image/svg+xml;base64,%s\"></xi:include>"
+      "</svg>";
+
+    /* FIXME: I've added 64 in the hope it will cover the size of the
+       width and height strings and things.  */
+    int buffer_size = SBYTES (encoded_contents) + strlen (wrapper) + 64;
+
+    value = image_spec_value (img->spec, QCforeground, NULL);
+    if (!NILP (value))
+      {
+        foreground = image_alloc_image_color (f, img, value, img->frame_foreground);
+      }
+    value = image_spec_value (img->spec, QCbackground, NULL);
+    if (!NILP (value))
+      {
+        background = image_alloc_image_color (f, img, value, img->frame_background);
+        img->background = background;
+        img->background_valid = 1;
+      }
+
+    wrapped_contents = malloc (buffer_size);
+
+    if (!wrapped_contents
+        || buffer_size <= snprintf (wrapped_contents, buffer_size, wrapper,
+                                    foreground & 0xFFFFFF, width, height,
+                                    dimension_data.width, dimension_data.height,
+                                    background & 0xFFFFFF, SSDATA (encoded_contents)))
+      goto rsvg_error;
+
+    wrapped_size = strlen (wrapped_contents);
+  }
+
+  /* Now we parse the wrapped version.  */
+
+#if LIBRSVG_CHECK_VERSION (2, 32, 0)
+  input_stream = g_memory_input_stream_new_from_data (wrapped_contents, wrapped_size, NULL);
+  base_file = filename ? g_file_new_for_path (filename) : NULL;
+  rsvg_handle = rsvg_handle_new_from_stream_sync (input_stream, base_file,
+						  RSVG_HANDLE_FLAGS_NONE,
+						  NULL, &err);
+  if (base_file)
+    g_object_unref (base_file);
+  g_object_unref (input_stream);
+
+  /* Check rsvg_handle too, to avoid librsvg 2.40.13 bug (Bug#36773#26).  */
+  if (!rsvg_handle || err) goto rsvg_error;
+#else
+  /* Make a handle to a new rsvg object.  */
+  rsvg_handle = rsvg_handle_new ();
+  eassume (rsvg_handle);
+
+  /* Set base_uri for properly handling referenced images (via 'href').
+     See rsvg bug 596114 - "image refs are relative to curdir, not .svg file"
+     <https://gitlab.gnome.org/GNOME/librsvg/issues/33>. */
+  if (filename)
+    rsvg_handle_set_base_uri (rsvg_handle, filename);
+
+  /* Parse the contents argument and fill in the rsvg_handle.  */
+  rsvg_handle_write (rsvg_handle, (unsigned char *) wrapped_contents, wrapped_size, &err);
+  if (err) goto rsvg_error;
+
   /* The parsing is complete, rsvg_handle is ready to used, close it
      for further writes.  */
   rsvg_handle_close (rsvg_handle, &err);
@@ -9728,6 +9850,7 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
   pixbuf = rsvg_handle_get_pixbuf (rsvg_handle);
   if (!pixbuf) goto rsvg_error;
   g_object_unref (rsvg_handle);
+  free (wrapped_contents);
 
   /* Extract some meta data from the svg handle.  */
   width     = gdk_pixbuf_get_width (pixbuf);
@@ -9752,25 +9875,6 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
 
     init_color_table ();
 
-    /* Handle alpha channel by combining the image with a background
-       color.  */
-    Emacs_Color background;
-    Lisp_Object specified_bg = image_spec_value (img->spec, QCbackground, NULL);
-    if (!STRINGP (specified_bg)
-	|| !FRAME_TERMINAL (f)->defined_color_hook (f,
-                                                    SSDATA (specified_bg),
-                                                    &background,
-                                                    false,
-                                                    false))
-      FRAME_TERMINAL (f)->query_frame_background_color (f, &background);
-
-    /* SVG pixmaps specify transparency in the last byte, so right
-       shift 8 bits to get rid of it, since emacs doesn't support
-       transparency.  */
-    background.red   >>= 8;
-    background.green >>= 8;
-    background.blue  >>= 8;
-
     /* This loop handles opacity values, since Emacs assumes
        non-transparent images.  Each pixel must be "flattened" by
        calculating the resulting color, given the transparency of the
@@ -9784,14 +9888,7 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
 	    int blue    = *pixels++;
 	    int 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)));
-
-	    PUT_PIXEL (ximg, x, y, lookup_rgb_color (f, red, green, blue));
+	    PUT_PIXEL (ximg, x, y, lookup_rgb_color (f, red << 8, green << 8, blue << 8));
 	  }
 
 	pixels += rowstride - 4 * width;
@@ -9821,6 +9918,8 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
  rsvg_error:
   if (rsvg_handle)
     g_object_unref (rsvg_handle);
+  if (wrapped_contents)
+    free (wrapped_contents);
   /* 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);
@@ -10119,7 +10218,7 @@ DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0,
   ptrdiff_t id = -1;
 
   if (valid_image_p (spec))
-    id = lookup_image (SELECTED_FRAME (), spec);
+    id = lookup_image (SELECTED_FRAME (), spec, -1);
 
   debug_print (spec);
   return make_fixnum (id);
diff --git a/src/nsmenu.m b/src/nsmenu.m
index b7e4cbd565..e313fc03f4 100644
--- a/src/nsmenu.m
+++ b/src/nsmenu.m
@@ -1092,7 +1092,7 @@ - (Lisp_Object)runMenuAt: (NSPoint)p forFrame: (struct frame *)f
           continue;
         }
 
-      img_id = lookup_image (f, image);
+      img_id = lookup_image (f, image, -1);
       img = IMAGE_FROM_ID (f, img_id);
       prepare_image_for_display (f, img);
 
diff --git a/src/xdisp.c b/src/xdisp.c
index 140d134572..f05fc4cb37 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -5690,7 +5690,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
       else
 	{
 	  it->what = IT_IMAGE;
-	  it->image_id = lookup_image (it->f, value);
+	  it->image_id = lookup_image (it->f, value, it->face_id);
 	  it->position = start_pos;
 	  it->object = NILP (object) ? it->w->contents : object;
 	  it->method = GET_FROM_IMAGE;
@@ -22379,7 +22379,7 @@ push_prefix_prop (struct it *it, Lisp_Object prop)
   else if (IMAGEP (prop))
     {
       it->what = IT_IMAGE;
-      it->image_id = lookup_image (it->f, prop);
+      it->image_id = lookup_image (it->f, prop, it->face_id);
       it->method = GET_FROM_IMAGE;
     }
 #endif /* HAVE_WINDOW_SYSTEM */
@@ -27262,7 +27262,7 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop,
 	  if (FRAME_WINDOW_P (it->f)
 	      && valid_image_p (prop))
 	    {
-	      ptrdiff_t id = lookup_image (it->f, prop);
+	      ptrdiff_t id = lookup_image (it->f, prop, it->face_id);
 	      struct image *img = IMAGE_FROM_ID (it->f, id);
 
 	      return OK_PIXELS (width_p ? img->width : img->height);
-- 
2.26.1


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-05-09 19:54                         ` Alan Third
@ 2020-05-15 11:09                           ` Eli Zaretskii
  2020-05-15 21:40                             ` Alan Third
  0 siblings, 1 reply; 52+ messages in thread
From: Eli Zaretskii @ 2020-05-15 11:09 UTC (permalink / raw)
  To: Alan Third; +Cc: cpitclaudel, 40845, pipcet

> Date: Sat, 9 May 2020 20:54:15 +0100
> From: Alan Third <alan@idiocy.org>
> 
> On Sat, May 09, 2020 at 03:27:27PM +0100, Alan Third wrote:
> > On Sun, May 03, 2020 at 05:24:17PM +0100, Alan Third wrote:
> > > 
> > > I’ve attached a first pass. It solves 1 and 4 from the original bug
> > > report: scaling and setting the foreground colour.
> > 
> > Can someone please try the patch from the previous email on a non‐NS
> > platform and confirm whether or not the background colour in the image
> > matches the background colour of the text?
> > 
> > They don’t match here, but I strongly suspect that’s because the NS
> > port uses different colour spaces for images and everything else.
> 
> Apologies, please can someone try the attached patch.

I didn't yet have time to try that, but I haven't forgot.  Hope the
current tsunami on emacs-devel will soon calm down, and I will have
more time.





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-05-15 11:09                           ` Eli Zaretskii
@ 2020-05-15 21:40                             ` Alan Third
  2020-08-22 16:15                               ` Alan Third
  0 siblings, 1 reply; 52+ messages in thread
From: Alan Third @ 2020-05-15 21:40 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: cpitclaudel, 40845, pipcet

On Fri, May 15, 2020 at 02:09:56PM +0300, Eli Zaretskii wrote:
> > Date: Sat, 9 May 2020 20:54:15 +0100
> > From: Alan Third <alan@idiocy.org>
> > 
> > On Sat, May 09, 2020 at 03:27:27PM +0100, Alan Third wrote:
> > > On Sun, May 03, 2020 at 05:24:17PM +0100, Alan Third wrote:
> > > > 
> > > > I’ve attached a first pass. It solves 1 and 4 from the original bug
> > > > report: scaling and setting the foreground colour.
> > > 
> > > Can someone please try the patch from the previous email on a non‐NS
> > > platform and confirm whether or not the background colour in the image
> > > matches the background colour of the text?
> > > 
> > > They don’t match here, but I strongly suspect that’s because the NS
> > > port uses different colour spaces for images and everything else.
> > 
> > Apologies, please can someone try the attached patch.
> 
> I didn't yet have time to try that, but I haven't forgot.  Hope the
> current tsunami on emacs-devel will soon calm down, and I will have
> more time.

Take as long as you need, I'm in no great hurry. I still need to work
out how to calculate whether I should be using the mouse face and
decide exactly how to handle flushing an image from the cache as
it's somewhat broken in that patch.
-- 
Alan Third





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-05-15 21:40                             ` Alan Third
@ 2020-08-22 16:15                               ` Alan Third
  2020-08-22 16:28                                 ` Lars Ingebrigtsen
  2020-08-22 16:54                                 ` Eli Zaretskii
  0 siblings, 2 replies; 52+ messages in thread
From: Alan Third @ 2020-08-22 16:15 UTC (permalink / raw)
  To: Eli Zaretskii, cpitclaudel, 40845, pipcet

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

On Fri, May 15, 2020 at 11:40:53PM +0200, Alan Third wrote:
> 
> Take as long as you need, I'm in no great hurry. I still need to work
> out how to calculate whether I should be using the mouse face and
> decide exactly how to handle flushing an image from the cache as
> it's somewhat broken in that patch.

I still don't know how to use the mouse face. I couldn't see any way
to detect if it's in use when we first load the image in xdisp.c.

Most likely I've missed something, but if not then I worry that the
easiest fix may be to actually support transparency when we draw to
the screen instead of generating background colours when we load the
images. I suspect we do it the way we do because it would have been
slow on older machines, but modern machines should be able to handle
it quickly via XRender and friends.

As for the cache I decided to just delete all images that match the
image spec, no matter what colours they use. It seems to me to be the
safest option, as we don't want users flushing an image from the
cache to display an updated version, only for the old one to reappear
when the face changes.
-- 
Alan Third

[-- Attachment #2: 0001-Set-basic-SVG-attributes-bug-40845.patch --]
[-- Type: text/plain, Size: 27556 bytes --]

From e3ef587f86e3fe0fba1de80c070d495e06148c1b Mon Sep 17 00:00:00 2001
From: Alan Third <alan@idiocy.org>
Date: Sun, 3 May 2020 17:09:31 +0100
Subject: [PATCH] Set basic SVG attributes (bug#40845)

* test/manual/image-transforms-tests.el: Replace hard-coded colors
with defaults.
* src/dispextern.h (struct image):
* src/image.c (search_image_cache):
(xbm_load_image):
(xbm_load):
(pbm_load): Rename from frame to face where relevant.
(svg_load_image): Parse the image to find out the size, then wrap it
in another SVG to set a new size and colors, etc.
(lookup_image): Use the face colors instead of the frame colors.
(search_image_cache): Add ability to ignore the face colors.
(uncache_image): Uncache all copies of the image that share the spec,
even if the face colors don't match.
---
 lisp/net/shr.el                       |  17 ---
 src/dispextern.h                      |   6 +-
 src/gtkutil.c                         |   2 +-
 src/image.c                           | 205 ++++++++++++++++++++------
 src/nsmenu.m                          |   2 +-
 src/xdisp.c                           |   6 +-
 test/manual/image-transforms-tests.el |  50 +++----
 7 files changed, 189 insertions(+), 99 deletions(-)

diff --git a/lisp/net/shr.el b/lisp/net/shr.el
index ddd8112721..24595301b7 100644
--- a/lisp/net/shr.el
+++ b/lisp/net/shr.el
@@ -1209,25 +1209,8 @@ shr-parse-image-data
             ;; that are non-ASCII.
 	    (shr-dom-to-xml
 	     (libxml-parse-xml-region (point) (point-max)) 'utf-8)))
-    ;; SVG images often do not have a specified foreground/background
-    ;; color, so wrap them in styles.
-    (when (and (display-images-p)
-               (eq content-type 'image/svg+xml))
-      (setq data (svg--wrap-svg data)))
     (list data content-type)))
 
-(defun svg--wrap-svg (data)
-  "Add a default foreground colour to SVG images."
-  (let ((size (image-size (create-image data nil t :scaling 1) t)))
-    (with-temp-buffer
-      (insert
-       (format
-        "<svg xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:xi=\"http://www.w3.org/2001/XInclude\" style=\"color: %s;\" viewBox=\"0 0 %d %d\"> <xi:include href=\"data:image/svg+xml;base64,%s\"></xi:include></svg>"
-        (face-foreground 'default)
-        (car size) (cdr size)
-        (base64-encode-string data t)))
-      (buffer-string))))
-
 (defun shr-image-displayer (content-function)
   "Return a function to display an image.
 CONTENT-FUNCTION is a function to retrieve an image for a cid url that
diff --git a/src/dispextern.h b/src/dispextern.h
index 311867a0c8..88bbb71fb9 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -3056,9 +3056,9 @@ reset_mouse_highlight (Mouse_HLInfo *hlinfo)
      if necessary.  */
   unsigned long background;
 
-  /* Foreground and background colors of the frame on which the image
+  /* Foreground and background colors of the face on which the image
      is created.  */
-  unsigned long frame_foreground, frame_background;
+  unsigned long face_foreground, face_background;
 
   /* True if this image has a `transparent' background -- that is, is
      uses an image mask.  The accessor macro for this is
@@ -3475,7 +3475,7 @@ #define TRY_WINDOW_IGNORE_FONTS_CHANGE	(1 << 1)
 void mark_image_cache (struct image_cache *);
 bool valid_image_p (Lisp_Object);
 void prepare_image_for_display (struct frame *, struct image *);
-ptrdiff_t lookup_image (struct frame *, Lisp_Object);
+ptrdiff_t lookup_image (struct frame *, Lisp_Object, int face_id);
 
 #if defined HAVE_X_WINDOWS || defined USE_CAIRO || defined HAVE_NS
 #define RGB_PIXEL_COLOR unsigned long
diff --git a/src/gtkutil.c b/src/gtkutil.c
index 1fe160acca..fafd94c0f7 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -5113,7 +5113,7 @@ update_frame_tool_bar (struct frame *f)
           else
             idx = -1;
 
-          img_id = lookup_image (f, image);
+          img_id = lookup_image (f, image, -1);
           img = IMAGE_FROM_ID (f, img_id);
           prepare_image_for_display (f, img);
 
diff --git a/src/image.c b/src/image.c
index 123de54ba2..297278ec9a 100644
--- a/src/image.c
+++ b/src/image.c
@@ -1081,7 +1081,7 @@ DEFUN ("image-size", Fimage_size, Simage_size, 1, 3, 0,
   if (valid_image_p (spec))
     {
       struct frame *f = decode_window_system_frame (frame);
-      ptrdiff_t id = lookup_image (f, spec);
+      ptrdiff_t id = lookup_image (f, spec, -1);
       struct image *img = IMAGE_FROM_ID (f, id);
       int width = img->width + 2 * img->hmargin;
       int height = img->height + 2 * img->vmargin;
@@ -1111,7 +1111,7 @@ DEFUN ("image-mask-p", Fimage_mask_p, Simage_mask_p, 1, 2, 0,
   if (valid_image_p (spec))
     {
       struct frame *f = decode_window_system_frame (frame);
-      ptrdiff_t id = lookup_image (f, spec);
+      ptrdiff_t id = lookup_image (f, spec, -1);
       struct image *img = IMAGE_FROM_ID (f, id);
       if (img->mask)
 	mask = Qt;
@@ -1134,7 +1134,7 @@ DEFUN ("image-metadata", Fimage_metadata, Simage_metadata, 1, 2, 0,
   if (valid_image_p (spec))
     {
       struct frame *f = decode_window_system_frame (frame);
-      ptrdiff_t id = lookup_image (f, spec);
+      ptrdiff_t id = lookup_image (f, spec, -1);
       struct image *img = IMAGE_FROM_ID (f, id);
       ext = img->lisp_data;
     }
@@ -1611,7 +1611,9 @@ equal_lists (Lisp_Object a, Lisp_Object b)
 /* Find an image matching SPEC in the cache, and return it.  If no
    image is found, return NULL.  */
 static struct image *
-search_image_cache (struct frame *f, Lisp_Object spec, EMACS_UINT hash)
+search_image_cache (struct frame *f, Lisp_Object spec, EMACS_UINT hash,
+                    unsigned long foreground, unsigned long background,
+                    bool ignore_colors)
 {
   struct image *img;
   struct image_cache *c = FRAME_IMAGE_CACHE (f);
@@ -1634,8 +1636,8 @@ search_image_cache (struct frame *f, Lisp_Object spec, EMACS_UINT hash)
   for (img = c->buckets[i]; img; img = img->next)
     if (img->hash == hash
 	&& equal_lists (img->spec, spec)
-	&& img->frame_foreground == FRAME_FOREGROUND_PIXEL (f)
-	&& img->frame_background == FRAME_BACKGROUND_PIXEL (f))
+	&& (ignore_colors || (img->face_foreground == foreground
+                              && img->face_background == background)))
       break;
   return img;
 }
@@ -1646,8 +1648,13 @@ search_image_cache (struct frame *f, Lisp_Object spec, EMACS_UINT hash)
 static void
 uncache_image (struct frame *f, Lisp_Object spec)
 {
-  struct image *img = search_image_cache (f, spec, sxhash (spec));
-  if (img)
+  struct image *img;
+
+  /* Because the background colors are based on the current face, we
+     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, sxhash (spec), 0, 0, true)))
     {
       free_image (f, img);
       /* As display glyphs may still be referring to the image ID, we
@@ -2133,7 +2140,17 @@ image_set_transform (struct frame *f, struct image *img)
 
   /* Determine size.  */
   int width, height;
-  compute_image_size (img->width, img->height, img->spec, &width, &height);
+
+#ifdef HAVE_RSVG
+  /* SVGs are pre-scaled to the correct size.  */
+  if (EQ (image_spec_value (img->spec, QCtype, NULL), Qsvg))
+    {
+      width = img->width;
+      height = img->height;
+    }
+  else
+#endif
+    compute_image_size (img->width, img->height, img->spec, &width, &height);
 
   /* Determine rotation.  */
   double rotation = 0.0;
@@ -2312,11 +2329,16 @@ image_set_transform (struct frame *f, struct image *img)
    SPEC must be a valid Lisp image specification (see valid_image_p).  */
 
 ptrdiff_t
-lookup_image (struct frame *f, Lisp_Object spec)
+lookup_image (struct frame *f, Lisp_Object spec, int face_id)
 {
   struct image *img;
   EMACS_UINT hash;
 
+  struct face *face = (face_id >= 0) ? FACE_FROM_ID (f, face_id)
+    : FACE_FROM_ID_OR_NULL (f, DEFAULT_FACE_ID);
+  unsigned long foreground = FACE_COLOR_TO_PIXEL (face->foreground, f);
+  unsigned long background = FACE_COLOR_TO_PIXEL (face->background, f);
+
   /* F must be a window-system frame, and SPEC must be a valid image
      specification.  */
   eassert (FRAME_WINDOW_P (f));
@@ -2324,7 +2346,7 @@ lookup_image (struct frame *f, Lisp_Object spec)
 
   /* Look up SPEC in the hash table of the image cache.  */
   hash = sxhash (spec);
-  img = search_image_cache (f, spec, hash);
+  img = search_image_cache (f, spec, hash, foreground, background, true);
   if (img && img->load_failed_p)
     {
       free_image (f, img);
@@ -2337,9 +2359,9 @@ lookup_image (struct frame *f, Lisp_Object spec)
       block_input ();
       img = make_image (spec, hash);
       cache_image (f, img);
+      img->face_foreground = foreground;
+      img->face_background = background;
       img->load_failed_p = ! img->type->load (f, img);
-      img->frame_foreground = FRAME_FOREGROUND_PIXEL (f);
-      img->frame_background = FRAME_BACKGROUND_PIXEL (f);
 
       /* If we can't load the image, and we don't have a width and
 	 height, use some arbitrary width and height so that we can
@@ -2393,8 +2415,7 @@ lookup_image (struct frame *f, Lisp_Object spec)
 	      if (!NILP (bg))
 		{
 		  img->background
-		    = image_alloc_image_color (f, img, bg,
-                                               FRAME_BACKGROUND_PIXEL (f));
+		    = image_alloc_image_color (f, img, bg, background);
 		  img->background_valid = 1;
 		}
 	    }
@@ -3667,8 +3688,8 @@ xbm_load_image (struct frame *f, struct image *img, char *contents, char *end)
 			     &data, 0);
   if (rc)
     {
-      unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
-      unsigned long background = FRAME_BACKGROUND_PIXEL (f);
+      unsigned long foreground = img->face_foreground;
+      unsigned long background = img->face_background;
       bool non_default_colors = 0;
       Lisp_Object value;
 
@@ -3764,8 +3785,8 @@ xbm_load (struct frame *f, struct image *img)
     {
       struct image_keyword fmt[XBM_LAST];
       Lisp_Object data;
-      unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
-      unsigned long background = FRAME_BACKGROUND_PIXEL (f);
+      unsigned long foreground = img->face_foreground;
+      unsigned long background = img->face_background;
       bool non_default_colors = 0;
       char *bits;
       bool parsed_p;
@@ -6125,8 +6146,8 @@ pbm_load (struct frame *f, struct image *img)
       unsigned char c = 0;
       int g;
       struct image_keyword fmt[PBM_LAST];
-      unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
-      unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
+      unsigned long fg = img->face_foreground;
+      unsigned long bg = img->face_background;
       /* Parse the image specification.  */
       memcpy (fmt, pbm_format, sizeof fmt);
       parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
@@ -9433,6 +9454,7 @@ DEFUN ("imagemagick-types", Fimagemagick_types, Simagemagick_types, 0, 0, 0,
   SVG_ALGORITHM,
   SVG_HEURISTIC_MASK,
   SVG_MASK,
+  SVG_FOREGROUND,
   SVG_BACKGROUND,
   SVG_LAST
 };
@@ -9451,6 +9473,7 @@ DEFUN ("imagemagick-types", Fimagemagick_types, Simagemagick_types, 0, 0, 0,
   {":conversion",	IMAGE_DONT_CHECK_VALUE_TYPE,		0},
   {":heuristic-mask",	IMAGE_DONT_CHECK_VALUE_TYPE,		0},
   {":mask",		IMAGE_DONT_CHECK_VALUE_TYPE,		0},
+  {":foreground",	IMAGE_STRING_OR_NIL_VALUE,		0},
   {":background",	IMAGE_STRING_OR_NIL_VALUE,		0}
 };
 
@@ -9715,6 +9738,8 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
   int height;
   const guint8 *pixels;
   int rowstride;
+  char *wrapped_contents = NULL;
+  ptrdiff_t wrapped_size;
 
 #if ! GLIB_CHECK_VERSION (2, 36, 0)
   /* g_type_init is a glib function that must be called prior to
@@ -9722,6 +9747,8 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
   g_type_init ();
 #endif
 
+  /* Parse the unmodified SVG data so we can get it's initial size.  */
+
 #if LIBRSVG_CHECK_VERSION (2, 32, 0)
   GInputStream *input_stream
     = g_memory_input_stream_new_from_data (contents, size, NULL);
@@ -9750,6 +9777,107 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
   rsvg_handle_write (rsvg_handle, (unsigned char *) contents, size, &err);
   if (err) goto rsvg_error;
 
+  /* The parsing is complete, rsvg_handle is ready to used, close it
+     for further writes.  */
+  rsvg_handle_close (rsvg_handle, &err);
+  if (err) goto rsvg_error;
+#endif
+
+  /* Get the image dimensions.  */
+  rsvg_handle_get_dimensions (rsvg_handle, &dimension_data);
+
+  /* We are now done with the unmodified data.  */
+  g_object_unref (rsvg_handle);
+
+  /* Calculate the final image size.  */
+  compute_image_size (dimension_data.width, dimension_data.height,
+                      img->spec, &width, &height);
+
+  /* Wrap the SVG data in another SVG.  This allows us to set the
+     width and height, as well as modify the foreground and background
+     colors.  */
+  {
+    Lisp_Object value;
+    unsigned long foreground = img->face_foreground;
+    unsigned long background = img->face_background;
+
+    Lisp_Object encoded_contents = Fbase64_encode_string
+      (make_unibyte_string (contents, size), Qt);
+
+    /* The wrapper sets the foreground color, width and height, and
+       viewBox must contain the dimensions of the original image.  It
+       also draws a rectangle over the whole space, set to the
+       background color, before including the original image. This
+       acts to set the background color, instead of leaving it
+       transparent.  */
+    const char *wrapper =
+      "<svg xmlns:xlink=\"http://www.w3.org/1999/xlink\" "
+      "xmlns:xi=\"http://www.w3.org/2001/XInclude\" "
+      "style=\"color: #%06X; fill: currentColor;\" "
+      "width=\"%d\" height=\"%d\" preserveAspectRatio=\"none\" "
+      "viewBox=\"0 0 %d %d\">"
+      "<rect width=\"100%%\" height=\"100%%\" fill=\"#%06X\"/>"
+      "<xi:include href=\"data:image/svg+xml;base64,%s\"></xi:include>"
+      "</svg>";
+
+    /* FIXME: I've added 64 in the hope it will cover the size of the
+       width and height strings and things.  */
+    int buffer_size = SBYTES (encoded_contents) + strlen (wrapper) + 64;
+
+    value = image_spec_value (img->spec, QCforeground, NULL);
+    if (!NILP (value))
+      {
+        foreground = image_alloc_image_color (f, img, value, img->face_foreground);
+      }
+    value = image_spec_value (img->spec, QCbackground, NULL);
+    if (!NILP (value))
+      {
+        background = image_alloc_image_color (f, img, value, img->face_background);
+        img->background = background;
+        img->background_valid = 1;
+      }
+
+    wrapped_contents = malloc (buffer_size);
+
+    if (!wrapped_contents
+        || buffer_size <= snprintf (wrapped_contents, buffer_size, wrapper,
+                                    foreground & 0xFFFFFF, width, height,
+                                    dimension_data.width, dimension_data.height,
+                                    background & 0xFFFFFF, SSDATA (encoded_contents)))
+      goto rsvg_error;
+
+    wrapped_size = strlen (wrapped_contents);
+  }
+
+  /* Now we parse the wrapped version.  */
+
+#if LIBRSVG_CHECK_VERSION (2, 32, 0)
+  input_stream = g_memory_input_stream_new_from_data (wrapped_contents, wrapped_size, NULL);
+  base_file = filename ? g_file_new_for_path (filename) : NULL;
+  rsvg_handle = rsvg_handle_new_from_stream_sync (input_stream, base_file,
+						  RSVG_HANDLE_FLAGS_NONE,
+						  NULL, &err);
+  if (base_file)
+    g_object_unref (base_file);
+  g_object_unref (input_stream);
+
+  /* Check rsvg_handle too, to avoid librsvg 2.40.13 bug (Bug#36773#26).  */
+  if (!rsvg_handle || err) goto rsvg_error;
+#else
+  /* Make a handle to a new rsvg object.  */
+  rsvg_handle = rsvg_handle_new ();
+  eassume (rsvg_handle);
+
+  /* Set base_uri for properly handling referenced images (via 'href').
+     See rsvg bug 596114 - "image refs are relative to curdir, not .svg file"
+     <https://gitlab.gnome.org/GNOME/librsvg/issues/33>. */
+  if (filename)
+    rsvg_handle_set_base_uri (rsvg_handle, filename);
+
+  /* Parse the contents argument and fill in the rsvg_handle.  */
+  rsvg_handle_write (rsvg_handle, (unsigned char *) wrapped_contents, wrapped_size, &err);
+  if (err) goto rsvg_error;
+
   /* The parsing is complete, rsvg_handle is ready to used, close it
      for further writes.  */
   rsvg_handle_close (rsvg_handle, &err);
@@ -9768,6 +9896,7 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
   pixbuf = rsvg_handle_get_pixbuf (rsvg_handle);
   if (!pixbuf) goto rsvg_error;
   g_object_unref (rsvg_handle);
+  free (wrapped_contents);
 
   /* Extract some meta data from the svg handle.  */
   width     = gdk_pixbuf_get_width (pixbuf);
@@ -9792,25 +9921,6 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
 
     init_color_table ();
 
-    /* Handle alpha channel by combining the image with a background
-       color.  */
-    Emacs_Color background;
-    Lisp_Object specified_bg = image_spec_value (img->spec, QCbackground, NULL);
-    if (!STRINGP (specified_bg)
-	|| !FRAME_TERMINAL (f)->defined_color_hook (f,
-                                                    SSDATA (specified_bg),
-                                                    &background,
-                                                    false,
-                                                    false))
-      FRAME_TERMINAL (f)->query_frame_background_color (f, &background);
-
-    /* SVG pixmaps specify transparency in the last byte, so right
-       shift 8 bits to get rid of it, since emacs doesn't support
-       transparency.  */
-    background.red   >>= 8;
-    background.green >>= 8;
-    background.blue  >>= 8;
-
     /* This loop handles opacity values, since Emacs assumes
        non-transparent images.  Each pixel must be "flattened" by
        calculating the resulting color, given the transparency of the
@@ -9822,16 +9932,11 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
 	    int red     = *pixels++;
 	    int green   = *pixels++;
 	    int blue    = *pixels++;
-	    int 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)));
+            /* Skip opacity.  */
+	    pixels++;
 
-	    PUT_PIXEL (ximg, x, y, lookup_rgb_color (f, red, green, blue));
+	    PUT_PIXEL (ximg, x, y, lookup_rgb_color (f, red << 8, green << 8, blue << 8));
 	  }
 
 	pixels += rowstride - 4 * width;
@@ -9861,6 +9966,8 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
  rsvg_error:
   if (rsvg_handle)
     g_object_unref (rsvg_handle);
+  if (wrapped_contents)
+    free (wrapped_contents);
   /* 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);
@@ -10159,7 +10266,7 @@ DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0,
   ptrdiff_t id = -1;
 
   if (valid_image_p (spec))
-    id = lookup_image (SELECTED_FRAME (), spec);
+    id = lookup_image (SELECTED_FRAME (), spec, -1);
 
   debug_print (spec);
   return make_fixnum (id);
diff --git a/src/nsmenu.m b/src/nsmenu.m
index b7e4cbd565..e313fc03f4 100644
--- a/src/nsmenu.m
+++ b/src/nsmenu.m
@@ -1092,7 +1092,7 @@ - (Lisp_Object)runMenuAt: (NSPoint)p forFrame: (struct frame *)f
           continue;
         }
 
-      img_id = lookup_image (f, image);
+      img_id = lookup_image (f, image, -1);
       img = IMAGE_FROM_ID (f, img_id);
       prepare_image_for_display (f, img);
 
diff --git a/src/xdisp.c b/src/xdisp.c
index ad03ac4605..764d5345f2 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -5696,7 +5696,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
       else
 	{
 	  it->what = IT_IMAGE;
-	  it->image_id = lookup_image (it->f, value);
+	  it->image_id = lookup_image (it->f, value, it->face_id);
 	  it->position = start_pos;
 	  it->object = NILP (object) ? it->w->contents : object;
 	  it->method = GET_FROM_IMAGE;
@@ -22434,7 +22434,7 @@ push_prefix_prop (struct it *it, Lisp_Object prop)
   else if (IMAGEP (prop))
     {
       it->what = IT_IMAGE;
-      it->image_id = lookup_image (it->f, prop);
+      it->image_id = lookup_image (it->f, prop, it->face_id);
       it->method = GET_FROM_IMAGE;
     }
 #endif /* HAVE_WINDOW_SYSTEM */
@@ -27335,7 +27335,7 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop,
 	  if (FRAME_WINDOW_P (it->f)
 	      && valid_image_p (prop))
 	    {
-	      ptrdiff_t id = lookup_image (it->f, prop);
+	      ptrdiff_t id = lookup_image (it->f, prop, it->face_id);
 	      struct image *img = IMAGE_FROM_ID (it->f, id);
 
 	      return OK_PIXELS (width_p ? img->width : img->height);
diff --git a/test/manual/image-transforms-tests.el b/test/manual/image-transforms-tests.el
index 0ebd5c7a19..02607e6367 100644
--- a/test/manual/image-transforms-tests.el
+++ b/test/manual/image-transforms-tests.el
@@ -48,24 +48,24 @@ test-cropping
   (let ((image "<svg height='30' width='30'>
                   <rect x='0' y='0' width='10' height='10'/>
                   <rect x='10' y='10' width='10' height='10'
-                        style='fill:none;stroke-width:1;stroke:#000'/>
-                  <line x1='10' y1='10' x2='20' y2='20' style='stroke:#000'/>
-                  <line x1='20' y1='10' x2='10' y2='20' style='stroke:#000'/>
+                        style='fill:none;stroke-width:1;stroke:currentColor'/>
+                  <line x1='10' y1='10' x2='20' y2='20' style='stroke:currentColor'/>
+                  <line x1='20' y1='10' x2='10' y2='20' style='stroke:currentColor'/>
                   <rect x='20' y='20' width='10' height='10'
-                        style='fill:none;stroke-width:1;stroke:#000'/>
+                        style='fill:none;stroke-width:1;stroke:currentColor'/>
                 </svg>")
         (top-left "<svg height='10' width='10'>
                      <rect x='0' y='0' width='10' height='10'/>
                    </svg>")
         (middle "<svg height='10' width='10'>
                    <rect x='0' y='0' width='10' height='10'
-                         style='fill:none;stroke-width:1;stroke:#000'/>
-                   <line x1='0' y1='0' x2='10' y2='10' style='stroke:#000'/>
-                   <line x1='10' y1='0' x2='0' y2='10' style='stroke:#000'/>
+                         style='fill:none;stroke-width:1;stroke:currentColor'/>
+                   <line x1='0' y1='0' x2='10' y2='10' style='stroke:currentColor'/>
+                   <line x1='10' y1='0' x2='0' y2='10' style='stroke:currentColor'/>
                  </svg>")
         (bottom-right "<svg height='10' width='10'>
                          <rect x='0' y='0' width='10' height='10'
-                               style='fill:none;stroke-width:1;stroke:#000'/>
+                               style='fill:none;stroke-width:1;stroke:currentColor'/>
                        </svg>"))
     (insert-header "Test Crop: cropping an image (only works with ImageMagick)")
     (insert-test "all params" top-left image '(:crop (10 10 0 0)))
@@ -77,23 +77,23 @@ test-cropping
 (defun test-scaling ()
   (let ((image "<svg height='10' width='10'>
                   <rect x='0' y='0' width='10' height='10'
-                        style='fill:none;stroke-width:1;stroke:#000'/>
-                  <line x1='0' y1='0' x2='10' y2='10' style='stroke:#000'/>
-                  <line x1='10' y1='0' x2='0' y2='10' style='stroke:#000'/>
+                        style='fill:none;stroke-width:1;stroke:currentColor'/>
+                  <line x1='0' y1='0' x2='10' y2='10' style='stroke:currentColor'/>
+                  <line x1='10' y1='0' x2='0' y2='10' style='stroke:currentColor'/>
                 </svg>")
         (large "<svg height='20' width='20'>
                   <rect x='0' y='0' width='20' height='20'
-                        style='fill:none;stroke-width:2;stroke:#000'/>
+                        style='fill:none;stroke-width:2;stroke:currentColor'/>
                   <line x1='0' y1='0' x2='20' y2='20'
-                        style='stroke-width:2;stroke:#000'/>
+                        style='stroke-width:2;stroke:currentColor'/>
                   <line x1='20' y1='0' x2='0' y2='20'
-                        style='stroke-width:2;stroke:#000'/>
+                        style='stroke-width:2;stroke:currentColor'/>
                 </svg>")
         (small "<svg height='5' width='5'>
                   <rect x='0' y='0' width='4' height='4'
-                        style='fill:none;stroke-width:1;stroke:#000'/>
-                  <line x1='0' y1='0' x2='4' y2='4' style='stroke:#000'/>
-                  <line x1='4' y1='0' x2='0' y2='4' style='stroke:#000'/>
+                        style='fill:none;stroke-width:1;stroke:currentColor'/>
+                  <line x1='0' y1='0' x2='4' y2='4' style='stroke:currentColor'/>
+                  <line x1='4' y1='0' x2='0' y2='4' style='stroke:currentColor'/>
                 </svg>"))
     (insert-header "Test Scaling: resize an image (pixelization may occur)")
     (insert-test "1x" image image '(:scale 1))
@@ -107,27 +107,27 @@ test-scaling
 (defun test-scaling-rotation ()
   (let ((image "<svg height='20' width='20'>
                   <rect x='0' y='0' width='20' height='20'
-                        style='fill:none;stroke-width:1;stroke:#000'/>
+                        style='fill:none;stroke-width:1;stroke:currentColor'/>
                   <rect x='0' y='0' width='10' height='10'
-                        style='fill:#000'/>
+                        style='fill:currentColor'/>
                 </svg>")
         (x2-90 "<svg height='40' width='40'>
                   <rect x='0' y='0' width='40' height='40'
-                        style='fill:none;stroke-width:1;stroke:#000'/>
+                        style='fill:none;stroke-width:1;stroke:currentColor'/>
                   <rect x='20' y='0' width='20' height='20'
-                        style='fill:#000'/>
+                        style='fill:currentColor'/>
                 </svg>")
         (x2--90 "<svg height='40' width='40'>
                    <rect x='0' y='0' width='40' height='40'
-                         style='fill:none;stroke-width:1;stroke:#000'/>
+                         style='fill:none;stroke-width:1;stroke:currentColor'/>
                    <rect x='0' y='20' width='20' height='20'
-                         style='fill:#000'/>
+                         style='fill:currentColor'/>
                  </svg>")
         (x0.5-180 "<svg height='10' width='10'>
                      <rect x='0' y='0' width='10' height='10'
-                           style='fill:none;stroke-width:1;stroke:#000'/>
+                           style='fill:none;stroke-width:1;stroke:currentColor'/>
                      <rect x='5' y='5' width='5' height='5'
-                           style='fill:#000'/>
+                           style='fill:currentColor'/>
                    </svg>"))
     (insert-header "Test Scaling and Rotation: resize and rotate an image (pixelization may occur)")
     (insert-test "1x, 0 degrees" image image '(:scale 1 :rotation 0))
-- 
2.26.1


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-08-22 16:15                               ` Alan Third
@ 2020-08-22 16:28                                 ` Lars Ingebrigtsen
  2020-08-22 16:54                                 ` Eli Zaretskii
  1 sibling, 0 replies; 52+ messages in thread
From: Lars Ingebrigtsen @ 2020-08-22 16:28 UTC (permalink / raw)
  To: Alan Third; +Cc: cpitclaudel, pipcet, 40845

Alan Third <alan@idiocy.org> writes:

> As for the cache I decided to just delete all images that match the
> image spec, no matter what colours they use. It seems to me to be the
> safest option, as we don't want users flushing an image from the
> cache to display an updated version, only for the old one to reappear
> when the face changes.

Makes sense.

I've tried your patch set, and it fixes the test case in this bug report
for me (under Debian).

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-08-22 16:15                               ` Alan Third
  2020-08-22 16:28                                 ` Lars Ingebrigtsen
@ 2020-08-22 16:54                                 ` Eli Zaretskii
  2020-08-22 18:57                                   ` Alan Third
  1 sibling, 1 reply; 52+ messages in thread
From: Eli Zaretskii @ 2020-08-22 16:54 UTC (permalink / raw)
  To: Alan Third; +Cc: cpitclaudel, 40845, pipcet

> Date: Sat, 22 Aug 2020 18:15:15 +0200 (CEST)
> From: Alan Third <alan@idiocy.org>
> 
> I still don't know how to use the mouse face. I couldn't see any way
> to detect if it's in use when we first load the image in xdisp.c.

Can you please remind me what was the problem?  The bug discussion is
very long, and I didn't have time/patience to find the mouse face
bits.

> -ptrdiff_t lookup_image (struct frame *, Lisp_Object);
> +ptrdiff_t lookup_image (struct frame *, Lisp_Object, int face_id);
                                                        ^^^^^^^^^^^
Please don't use names in prototypes, only types.

> +  /* Parse the unmodified SVG data so we can get it's initial size.  */
                                                    ^^^^
"its"

> +  /* The parsing is complete, rsvg_handle is ready to used, close it
                                             ^^^^^^^^^^^^^^^^
"is ready to be used"

> +       background color, before including the original image. This
                                                               ^^
Two spaces between sentences, please.

> +    Lisp_Object encoded_contents = Fbase64_encode_string
> +      (make_unibyte_string (contents, size), Qt);

Our style of breaking long lines like this one is different:

  Lisp_Object encoded_contents
    = Fbase64_encode_string (make_unibyte_string (contents, size), Qt);

> +    if (!NILP (value))
> +      {
> +        foreground = image_alloc_image_color (f, img, value, img->face_foreground);
> +      }

No need for braces when the block has only one line.

Thanks.





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-08-22 16:54                                 ` Eli Zaretskii
@ 2020-08-22 18:57                                   ` Alan Third
  2020-08-22 19:17                                     ` Eli Zaretskii
  0 siblings, 1 reply; 52+ messages in thread
From: Alan Third @ 2020-08-22 18:57 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: cpitclaudel, 40845, pipcet

On Sat, Aug 22, 2020 at 07:54:48PM +0300, Eli Zaretskii wrote:
> > Date: Sat, 22 Aug 2020 18:15:15 +0200 (CEST)
> > From: Alan Third <alan@idiocy.org>
> > 
> > I still don't know how to use the mouse face. I couldn't see any way
> > to detect if it's in use when we first load the image in xdisp.c.
> 
> Can you please remind me what was the problem?  The bug discussion is
> very long, and I didn't have time/patience to find the mouse face
> bits.

No problem.

Basically, if you try Clement's original example, when you move the
mouse over the image the background colour doesn't change to match the
rest of the line.

I'm picking up the background colour from the face stored in "it" in
push_prefix_prop or handle_single_display_spec in xdisp.c. As far as I
can tell one or both of these are the only places we can define the
image with the face colours as this is where we actually load the
image. The problem is that I don't see any way to work out if the
current image should use the background colour from the mouse face.

I know that later on we can do (s->hl == DRAW_MOUSE_FACE), but I don't
think those structures are built yet?

I've fixed the mistakes you pointed out. Thanks.
-- 
Alan Third





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-08-22 18:57                                   ` Alan Third
@ 2020-08-22 19:17                                     ` Eli Zaretskii
  2020-08-22 21:35                                       ` Alan Third
  0 siblings, 1 reply; 52+ messages in thread
From: Eli Zaretskii @ 2020-08-22 19:17 UTC (permalink / raw)
  To: Alan Third; +Cc: cpitclaudel, 40845, pipcet

> Date: Sat, 22 Aug 2020 20:57:59 +0200 (CEST)
> From: Alan Third <alan@idiocy.org>
> Cc: cpitclaudel@gmail.com, 40845@debbugs.gnu.org, pipcet@gmail.com
> 
> Basically, if you try Clement's original example, when you move the
> mouse over the image the background colour doesn't change to match the
> rest of the line.
> 
> I'm picking up the background colour from the face stored in "it" in
> push_prefix_prop or handle_single_display_spec in xdisp.c. As far as I
> can tell one or both of these are the only places we can define the
> image with the face colours as this is where we actually load the
> image. The problem is that I don't see any way to work out if the
> current image should use the background colour from the mouse face.
> 
> I know that later on we can do (s->hl == DRAW_MOUSE_FACE), but I don't
> think those structures are built yet?

I think you want to modify note_mouse_highlight so that it sets up the
frame's mouse-highlight info for image glyphs, like it currently does
for character glyphs.  It's possible this is all that needs to be
done; if not, we should see how to change show_mouse_face and its
subroutines to display images with mouse-highlight.

Let me know if you need more guidance.





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-08-22 19:17                                     ` Eli Zaretskii
@ 2020-08-22 21:35                                       ` Alan Third
  2020-08-23  5:47                                         ` Eli Zaretskii
  0 siblings, 1 reply; 52+ messages in thread
From: Alan Third @ 2020-08-22 21:35 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: cpitclaudel, 40845, pipcet

On Sat, Aug 22, 2020 at 10:17:53PM +0300, Eli Zaretskii wrote:
> > Date: Sat, 22 Aug 2020 20:57:59 +0200 (CEST)
> > From: Alan Third <alan@idiocy.org>
> > Cc: cpitclaudel@gmail.com, 40845@debbugs.gnu.org, pipcet@gmail.com
> > 
> > Basically, if you try Clement's original example, when you move the
> > mouse over the image the background colour doesn't change to match the
> > rest of the line.
> > 
> > I'm picking up the background colour from the face stored in "it" in
> > push_prefix_prop or handle_single_display_spec in xdisp.c. As far as I
> > can tell one or both of these are the only places we can define the
> > image with the face colours as this is where we actually load the
> > image. The problem is that I don't see any way to work out if the
> > current image should use the background colour from the mouse face.
> > 
> > I know that later on we can do (s->hl == DRAW_MOUSE_FACE), but I don't
> > think those structures are built yet?
> 
> I think you want to modify note_mouse_highlight so that it sets up the
> frame's mouse-highlight info for image glyphs, like it currently does
> for character glyphs.  It's possible this is all that needs to be
> done; if not, we should see how to change show_mouse_face and its
> subroutines to display images with mouse-highlight.
> 
> Let me know if you need more guidance.

Thanks for your help, and that certainly helped me understand a bit
more about how mouse highlighting works and I don't think setting the
background colour from a face is a practical way of doing this.

But I've just realised we don't need to do it. Masks provide this
functionality. If you want the background of your SVG to match the
background of the buffer, use a mask, which can be keyed off a
specific colour or whatever.

Unfortunately it won't work well for semi-transparent images, but I
think the only really practical solution for that is to introduce
proper transparency handling.

Therefore I think this patch is ready to go.
-- 
Alan Third





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-08-22 21:35                                       ` Alan Third
@ 2020-08-23  5:47                                         ` Eli Zaretskii
  2020-08-23  9:09                                           ` Alan Third
  0 siblings, 1 reply; 52+ messages in thread
From: Eli Zaretskii @ 2020-08-23  5:47 UTC (permalink / raw)
  To: Alan Third; +Cc: cpitclaudel, 40845, pipcet

> Date: Sat, 22 Aug 2020 23:35:46 +0200 (CEST)
> From: Alan Third <alan@idiocy.org>
> Cc: cpitclaudel@gmail.com, 40845@debbugs.gnu.org, pipcet@gmail.com
> 
> Therefore I think this patch is ready to go.

Thanks.  Before we install this, one question: is there a possibility
someone would want the previous behavior?





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-08-23  5:47                                         ` Eli Zaretskii
@ 2020-08-23  9:09                                           ` Alan Third
  2020-08-23  9:11                                             ` Eli Zaretskii
  0 siblings, 1 reply; 52+ messages in thread
From: Alan Third @ 2020-08-23  9:09 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: cpitclaudel, 40845, pipcet

On Sun, Aug 23, 2020 at 08:47:27AM +0300, Eli Zaretskii wrote:
> > Date: Sat, 22 Aug 2020 23:35:46 +0200 (CEST)
> > From: Alan Third <alan@idiocy.org>
> > Cc: cpitclaudel@gmail.com, 40845@debbugs.gnu.org, pipcet@gmail.com
> > 
> > Therefore I think this patch is ready to go.
> 
> Thanks.  Before we install this, one question: is there a possibility
> someone would want the previous behavior?

I don't think so. The resizing is plainly better, and if someone wants
to enforce a foreground and background colour they can still do that
with the :foreground and :background image properties.
-- 
Alan Third





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-08-23  9:09                                           ` Alan Third
@ 2020-08-23  9:11                                             ` Eli Zaretskii
  2020-08-23 11:48                                               ` Alan Third
  0 siblings, 1 reply; 52+ messages in thread
From: Eli Zaretskii @ 2020-08-23  9:11 UTC (permalink / raw)
  To: Alan Third; +Cc: cpitclaudel, 40845, pipcet

> Date: Sun, 23 Aug 2020 11:09:01 +0200 (CEST)
> From: Alan Third <alan@idiocy.org>
> Cc: cpitclaudel@gmail.com, 40845@debbugs.gnu.org, pipcet@gmail.com
> 
> > Thanks.  Before we install this, one question: is there a possibility
> > someone would want the previous behavior?
> 
> I don't think so. The resizing is plainly better, and if someone wants
> to enforce a foreground and background colour they can still do that
> with the :foreground and :background image properties.

OK, then let's say that last bit in the NEWS entry announcing this new
behavior.





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-08-23  9:11                                             ` Eli Zaretskii
@ 2020-08-23 11:48                                               ` Alan Third
  2020-08-23 12:05                                                 ` Eli Zaretskii
  0 siblings, 1 reply; 52+ messages in thread
From: Alan Third @ 2020-08-23 11:48 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: cpitclaudel, 40845, pipcet

On Sun, Aug 23, 2020 at 12:11:55PM +0300, Eli Zaretskii wrote:
> > Date: Sun, 23 Aug 2020 11:09:01 +0200 (CEST)
> > From: Alan Third <alan@idiocy.org>
> > Cc: cpitclaudel@gmail.com, 40845@debbugs.gnu.org, pipcet@gmail.com
> > 
> > > Thanks.  Before we install this, one question: is there a possibility
> > > someone would want the previous behavior?
> > 
> > I don't think so. The resizing is plainly better, and if someone wants
> > to enforce a foreground and background colour they can still do that
> > with the :foreground and :background image properties.
> 
> OK, then let's say that last bit in the NEWS entry announcing this new
> behavior.

Something like this?

*** The background and foreground of images now default to face colors.
To load images with the default frame colors use the ':foreground'
and ':background' image attributes, for example:

    (create-image "filename" nil nil
                  :foreground (face-attribute 'default :foreground)
                  :background (face-attribute 'default :background))

-- 
Alan Third





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-08-23 11:48                                               ` Alan Third
@ 2020-08-23 12:05                                                 ` Eli Zaretskii
  2020-08-23 12:19                                                   ` Alan Third
  0 siblings, 1 reply; 52+ messages in thread
From: Eli Zaretskii @ 2020-08-23 12:05 UTC (permalink / raw)
  To: Alan Third; +Cc: cpitclaudel, 40845, pipcet

> Date: Sun, 23 Aug 2020 13:48:45 +0200 (CEST)
> From: Alan Third <alan@idiocy.org>
> Cc: cpitclaudel@gmail.com, 40845@debbugs.gnu.org, pipcet@gmail.com
> 
> *** The background and foreground of images now default to face colors.
> To load images with the default frame colors use the ':foreground'
> and ':background' image attributes, for example:
> 
>     (create-image "filename" nil nil
>                   :foreground (face-attribute 'default :foreground)
>                   :background (face-attribute 'default :background))

Yes, thanks.  But maybe expand a bit about "the face colors" part (not
in the heading line, but in the body): what face is that, and when
will the colors be used (I understand they will be used only if the
image doesn't specify its own colors).





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-08-23 12:05                                                 ` Eli Zaretskii
@ 2020-08-23 12:19                                                   ` Alan Third
  2020-08-23 12:23                                                     ` Eli Zaretskii
  0 siblings, 1 reply; 52+ messages in thread
From: Alan Third @ 2020-08-23 12:19 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: cpitclaudel, 40845, pipcet

On Sun, Aug 23, 2020 at 03:05:24PM +0300, Eli Zaretskii wrote:
> 
> Yes, thanks.  But maybe expand a bit about "the face colors" part (not
> in the heading line, but in the body): what face is that, and when
> will the colors be used (I understand they will be used only if the
> image doesn't specify its own colors).

How's this?

---
*** The background and foreground of images now default to face
colors.  When an image doesn't specify a foreground or background
color, Emacs now uses colors from the face used to draw the
surrounding text instead of the frame's default colors.

To load images with the default frame colors use the ':foreground'
and ':background' image attributes, for example:

    (create-image "filename" nil nil
                  :foreground (face-attribute 'default :foreground)
                  :background (face-attribute 'default :background))

This change doesn't affect image types that do not support foreground
and background colors, such as png or jpeg.

-- 
Alan Third





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-08-23 12:19                                                   ` Alan Third
@ 2020-08-23 12:23                                                     ` Eli Zaretskii
  2020-08-23 15:29                                                       ` Alan Third
  0 siblings, 1 reply; 52+ messages in thread
From: Eli Zaretskii @ 2020-08-23 12:23 UTC (permalink / raw)
  To: Alan Third; +Cc: cpitclaudel, 40845, pipcet

> Date: Sun, 23 Aug 2020 14:19:28 +0200 (CEST)
> From: Alan Third <alan@idiocy.org>
> Cc: cpitclaudel@gmail.com, 40845@debbugs.gnu.org, pipcet@gmail.com
> 
> *** The background and foreground of images now default to face
> colors.  When an image doesn't specify a foreground or background
> color, Emacs now uses colors from the face used to draw the
> surrounding text instead of the frame's default colors.
> 
> To load images with the default frame colors use the ':foreground'
> and ':background' image attributes, for example:
> 
>     (create-image "filename" nil nil
>                   :foreground (face-attribute 'default :foreground)
>                   :background (face-attribute 'default :background))
> 
> This change doesn't affect image types that do not support foreground
> and background colors, such as png or jpeg.

Almost perfect: I would suggest to modify the last sentence so that it
tells which types of images do support this feature.

Thanks.





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-08-23 12:23                                                     ` Eli Zaretskii
@ 2020-08-23 15:29                                                       ` Alan Third
  2020-08-23 15:43                                                         ` Lars Ingebrigtsen
  0 siblings, 1 reply; 52+ messages in thread
From: Alan Third @ 2020-08-23 15:29 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: cpitclaudel, 40845-done, pipcet

On Sun, Aug 23, 2020 at 03:23:33PM +0300, Eli Zaretskii wrote:
> > Date: Sun, 23 Aug 2020 14:19:28 +0200 (CEST)
> > From: Alan Third <alan@idiocy.org>
> > Cc: cpitclaudel@gmail.com, 40845@debbugs.gnu.org, pipcet@gmail.com
> > 
> > *** The background and foreground of images now default to face
> > colors.  When an image doesn't specify a foreground or background
> > color, Emacs now uses colors from the face used to draw the
> > surrounding text instead of the frame's default colors.
> > 
> > To load images with the default frame colors use the ':foreground'
> > and ':background' image attributes, for example:
> > 
> >     (create-image "filename" nil nil
> >                   :foreground (face-attribute 'default :foreground)
> >                   :background (face-attribute 'default :background))
> > 
> > This change doesn't affect image types that do not support foreground
> > and background colors, such as png or jpeg.
> 
> Almost perfect: I would suggest to modify the last sentence so that it
> tells which types of images do support this feature.

Thanks. I've pushed it to master.
-- 
Alan Third





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-08-23 15:29                                                       ` Alan Third
@ 2020-08-23 15:43                                                         ` Lars Ingebrigtsen
  2020-08-23 16:08                                                           ` Alan Third
  0 siblings, 1 reply; 52+ messages in thread
From: Lars Ingebrigtsen @ 2020-08-23 15:43 UTC (permalink / raw)
  To: Alan Third; +Cc: cpitclaudel, 40845-done, pipcet

Alan Third <alan@idiocy.org> writes:

> Thanks. I've pushed it to master.

Great!

I'm getting this warning, though:

image.c: In function ‘lookup_image’:
image.c:2340:17: warning: potential null pointer dereference [-Wnull-dereference]
 2340 |   unsigned long background = FACE_COLOR_TO_PIXEL (face->background, f);
      |                 ^~~~~~~~~~
image.c:2339:17: warning: potential null pointer dereference [-Wnull-dereference]
 2339 |   unsigned long foreground = FACE_COLOR_TO_PIXEL (face->foreground, f);
      |                 ^~~~~~~~~~

This is on Debian/bullseye, with gcc (Debian 9.3.0-15) 9.3.0.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-08-23 15:43                                                         ` Lars Ingebrigtsen
@ 2020-08-23 16:08                                                           ` Alan Third
  2020-08-23 16:38                                                             ` Lars Ingebrigtsen
  0 siblings, 1 reply; 52+ messages in thread
From: Alan Third @ 2020-08-23 16:08 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: cpitclaudel, 40845-done, pipcet

On Sun, Aug 23, 2020 at 05:43:24PM +0200, Lars Ingebrigtsen wrote:
> Alan Third <alan@idiocy.org> writes:
> 
> > Thanks. I've pushed it to master.
> 
> Great!
> 
> I'm getting this warning, though:
> 
> image.c: In function ‘lookup_image’:
> image.c:2340:17: warning: potential null pointer dereference [-Wnull-dereference]
>  2340 |   unsigned long background = FACE_COLOR_TO_PIXEL (face->background, f);
>       |                 ^~~~~~~~~~
> image.c:2339:17: warning: potential null pointer dereference [-Wnull-dereference]
>  2339 |   unsigned long foreground = FACE_COLOR_TO_PIXEL (face->foreground, f);
>       |                 ^~~~~~~~~~
> 
> This is on Debian/bullseye, with gcc (Debian 9.3.0-15) 9.3.0.

I don't think I should have used FACE_FROM_ID_OR_NULL. I would hope
we're not going to be trying to load images without a default face
already defined.

I've pushed a fix.
-- 
Alan Third





^ permalink raw reply	[flat|nested] 52+ messages in thread

* bug#40845: SVG rendering issues
  2020-08-23 16:08                                                           ` Alan Third
@ 2020-08-23 16:38                                                             ` Lars Ingebrigtsen
  0 siblings, 0 replies; 52+ messages in thread
From: Lars Ingebrigtsen @ 2020-08-23 16:38 UTC (permalink / raw)
  To: Alan Third; +Cc: cpitclaudel, 40845-done, pipcet

Alan Third <alan@idiocy.org> writes:

> I don't think I should have used FACE_FROM_ID_OR_NULL. I would hope
> we're not going to be trying to load images without a default face
> already defined.
>
> I've pushed a fix.

Thanks; that fixes the warnings.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 52+ messages in thread

end of thread, other threads:[~2020-08-23 16:38 UTC | newest]

Thread overview: 52+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-04-25 12:19 bug#40845: SVG rendering issues Clément Pit-Claudel
2020-04-25 14:34 ` Pip Cet
2020-04-25 15:30   ` Eli Zaretskii
2020-04-25 15:48     ` Pip Cet
2020-04-25 16:10       ` Eli Zaretskii
2020-04-25 17:38         ` Pip Cet
2020-04-25 18:07           ` Eli Zaretskii
2020-04-25 19:41             ` Pip Cet
2020-04-25 20:11               ` Eli Zaretskii
2020-04-26 10:15                 ` Pip Cet
2020-04-26 14:38                   ` Eli Zaretskii
2020-04-26 19:00                     ` Pip Cet
2020-04-27 15:47                       ` Eli Zaretskii
2020-04-25 15:46   ` Eli Zaretskii
2020-04-25 16:42     ` Clément Pit-Claudel
2020-04-25 17:02       ` Eli Zaretskii
2020-04-25 17:24         ` Clément Pit-Claudel
2020-04-25 17:46           ` Alan Third
2020-04-25 18:07             ` Pip Cet
2020-04-26 21:17             ` Alan Third
2020-04-26 22:48               ` Clément Pit-Claudel
2020-04-27 15:22                 ` Alan Third
2020-04-27 16:04                   ` Clément Pit-Claudel
2020-05-03 14:13                 ` Alan Third
2020-05-03 14:18                   ` Lars Ingebrigtsen
2020-05-03 16:07                   ` Eli Zaretskii
2020-05-03 16:24                     ` Alan Third
2020-05-03 16:49                       ` Eli Zaretskii
2020-05-03 18:38                         ` Alan Third
2020-05-03 19:17                           ` Eli Zaretskii
2020-05-09 14:27                       ` Alan Third
2020-05-09 19:54                         ` Alan Third
2020-05-15 11:09                           ` Eli Zaretskii
2020-05-15 21:40                             ` Alan Third
2020-08-22 16:15                               ` Alan Third
2020-08-22 16:28                                 ` Lars Ingebrigtsen
2020-08-22 16:54                                 ` Eli Zaretskii
2020-08-22 18:57                                   ` Alan Third
2020-08-22 19:17                                     ` Eli Zaretskii
2020-08-22 21:35                                       ` Alan Third
2020-08-23  5:47                                         ` Eli Zaretskii
2020-08-23  9:09                                           ` Alan Third
2020-08-23  9:11                                             ` Eli Zaretskii
2020-08-23 11:48                                               ` Alan Third
2020-08-23 12:05                                                 ` Eli Zaretskii
2020-08-23 12:19                                                   ` Alan Third
2020-08-23 12:23                                                     ` Eli Zaretskii
2020-08-23 15:29                                                       ` Alan Third
2020-08-23 15:43                                                         ` Lars Ingebrigtsen
2020-08-23 16:08                                                           ` Alan Third
2020-08-23 16:38                                                             ` Lars Ingebrigtsen
2020-04-27  2:27               ` Eli Zaretskii

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).