unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Face transparency attribute
@ 2024-01-18  1:35 Sebastian Wålinder
  2024-01-18  7:14 ` Po Lu
  0 siblings, 1 reply; 6+ messages in thread
From: Sebastian Wålinder @ 2024-01-18  1:35 UTC (permalink / raw)
  To: emacs-devel

Hello!

Frames in Emacs recently got the option to set a transparency that makes all background colors in the frame transparent to the degree you set.

Is there any way to set the transparency on a particular face? I didn't find any way when looking through the documentation.

If not, are there any workarounds and would face local transparency be hard to implement?

I'd like to experiment with transparency, making the fringes for instance more transparent, as it's not a content area.

Thanks for any help!
Sebastian



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

* Re: Face transparency attribute
  2024-01-18  1:35 Face transparency attribute Sebastian Wålinder
@ 2024-01-18  7:14 ` Po Lu
  2024-03-17 23:02   ` Nate Sandy
  0 siblings, 1 reply; 6+ messages in thread
From: Po Lu @ 2024-01-18  7:14 UTC (permalink / raw)
  To: Sebastian Wålinder; +Cc: emacs-devel

Sebastian Wålinder <s.walinder@gmail.com> writes:

> Frames in Emacs recently got the option to set a transparency that
> makes all background colors in the frame transparent to the degree you
> set.
>
> Is there any way to set the transparency on a particular face? I
> didn't find any way when looking through the documentation.

There are as yet no provisions for configuring individual faces to
display at their own transparency levels.

> If not, are there any workarounds and would face local transparency be
> hard to implement?

It would not be prohibitively difficult, although most of our code
assumes that face colors are always opaque, which suggests two
approaches to implementing per-face transparency values: either to
extend face colors with an extra alpha channel, or to extend faces with
a new attribute specifying a transparency value.

The first would pose difficulties in the way of adapting the
window-system code charged with manipulating colors without regard to
the existence of an alpha channel, whereas the second would open a
semantic can of worms, raising questions such as how the new face
attribute should be disposed as two faces are merged.  Right now, most
such window-system code is jerry-rigged to introduce the alpha channel
at the stage where glyph backgrounds are drawn, and before the few
routines so affected colors are treated much as they have always been.

Neither approach is easy or exceptionally challenging, so interested
individuals are invited to chose whichever they should find more to
their liking.

> I'd like to experiment with transparency, making the fringes for
> instance more transparent, as it's not a content area.

The relevant code is in xterm.c and pgtkterm.c (*_draw_fringe_bitmap),
and godspeed.



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

* Re: Face transparency attribute
  2024-01-18  7:14 ` Po Lu
@ 2024-03-17 23:02   ` Nate Sandy
  2024-03-18  7:41     ` Protesilaos Stavrou
  2024-03-18 13:50     ` Po Lu
  0 siblings, 2 replies; 6+ messages in thread
From: Nate Sandy @ 2024-03-17 23:02 UTC (permalink / raw)
  To: Po Lu, Sebastian Wålinder; +Cc: emacs-devel

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

Po Lu <luangruo@yahoo.com> writes:

> Neither approach is easy or exceptionally challenging, so interested
> individuals are invited to chose whichever they should find more to
> their liking.

Hi Po,

I have written a patch for this for the pgtk backend and went with the
first route - supporting an alpha channel in face colors. I figured it's
nicer since we get alpha channels for all other text decorations as
well.

The way it works is that when painting a background color (one which
respects alpha-background), we instead compose it with the frame
background color via a re-implementation of CAIRO_OPERATOR_OVER. I
didn't find a way to do this with cairo itself without painting the
surface inbetween.

I also made sure that this patch integrates with alpha-background, which
is also my primary use case - fully hiding faces which don't respect
alpha-background.

The only syntax supported for transparency is gtk_parse_rgba's
`rgba(255,255,255,1.0)`. Maybe we would want support for `#ff00ff00` too?

One interesting quirk is that when changing the opacity of the `default`
face to less than 1, the whole background is fully transparent again. I
am not sure whether this is a fault in my code or because of some extra
logic regarding the `default` face.

Attached are a screenshot and the patch. I'd very much appreciate
feedback. If necessary I could also try to implement this for X and/or
terminals, however I don't have access to other platforms.

Best
Nate


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Add-rgba-support-for-faces-to-pgtk --]
[-- Type: text/x-patch, Size: 5071 bytes --]

From 63062b45d47f5054fc713f37daf3c0b88a7d5edf Mon Sep 17 00:00:00 2001
From: Nate Sandy <nsan@posteo.de>
Date: Sun, 17 Mar 2024 23:10:53 +0100
Subject: [PATCH] Add rgba support for faces to pgtk

---
 src/dispextern.h |  2 +-
 src/pgtkterm.c   | 56 ++++++++++++++++++++++++++++++++++--------------
 2 files changed, 41 insertions(+), 17 deletions(-)

diff --git a/src/dispextern.h b/src/dispextern.h
index 5387cb4560..1a6fbb2d95 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -50,7 +50,7 @@ #define No_Cursor (None)
 typedef struct
 {
   unsigned long pixel;
-  unsigned short red, green, blue;
+  unsigned short red, green, blue, alpha;
 } Emacs_Color;
 
 #ifndef HAVE_ANDROID
diff --git a/src/pgtkterm.c b/src/pgtkterm.c
index 1ec6bfcda4..b8284ba295 100644
--- a/src/pgtkterm.c
+++ b/src/pgtkterm.c
@@ -1677,6 +1677,7 @@ pgtk_compute_lighter_color (struct frame *f, unsigned long *pixel,
   new.red = min (0xffff, factor * color.red);
   new.green = min (0xffff, factor * color.green);
   new.blue = min (0xffff, factor * color.blue);
+  new.alpha = color.alpha;
 
   /* Calculate brightness of COLOR.  */
   bright = (2 * color.red + 3 * color.green + color.blue) / 6;
@@ -1706,7 +1707,8 @@ pgtk_compute_lighter_color (struct frame *f, unsigned long *pixel,
 	}
     }
 
-  new.pixel = (new.red >> 8 << 16
+  new.pixel = (new.alpha >> 8 << 24
+	       | new.red >> 8 << 16
 	       | new.green >> 8 << 8
 	       | new.blue >> 8);
 
@@ -1717,7 +1719,8 @@ pgtk_compute_lighter_color (struct frame *f, unsigned long *pixel,
       new.red = min (0xffff, delta + color.red);
       new.green = min (0xffff, delta + color.green);
       new.blue = min (0xffff, delta + color.blue);
-      new.pixel = (new.red >> 8 << 16
+      new.pixel = (new.alpha >> 8 << 24
+		   | new.red >> 8 << 16
 		   | new.green >> 8 << 8
 		   | new.blue >> 8);
     }
@@ -7046,7 +7049,9 @@ pgtk_parse_color (struct frame *f, const char *color_name,
       color->red = rgba.red * 65535;
       color->green = rgba.green * 65535;
       color->blue = rgba.blue * 65535;
-      color->pixel = ((color->red >> 8) << 16
+      color->alpha = rgba.alpha * 65535;
+      color->pixel = ((color->alpha >> 8) << 24
+		      | (color->red >> 8) << 16
 		      | (color->green >> 8) << 8
 		      | (color->blue >> 8) << 0);
       return 1;
@@ -7066,9 +7071,11 @@ pgtk_query_colors (struct frame *f, Emacs_Color * colors, int ncolors)
     {
       unsigned long pixel = colors[i].pixel;
       /* Convert to a 16 bit value in range 0 - 0xffff. */
+#define GetAValue(p) (((p) >> 24) & 0xff)
 #define GetRValue(p) (((p) >> 16) & 0xff)
 #define GetGValue(p) (((p) >> 8) & 0xff)
 #define GetBValue(p) (((p) >> 0) & 0xff)
+      colors[i].alpha = GetAValue (pixel) * 257;
       colors[i].red = GetRValue (pixel) * 257;
       colors[i].green = GetGValue (pixel) * 257;
       colors[i].blue = GetBValue (pixel) * 257;
@@ -7255,6 +7262,18 @@ pgtk_set_cr_source_with_gc_background (struct frame *f, Emacs_GC *gc,
 				 respects_alpha_background);
 }
 
+void
+pgtk_cr_operator_over (Emacs_Color a, Emacs_Color b, Emacs_Color *result) {
+  double a_alpha_norm = a.alpha / 65535.0;
+  double b_alpha_norm = b.alpha / 65535.0;
+
+  result->alpha = a_alpha_norm + b_alpha_norm * (1.0 - a_alpha_norm);
+  result->red = (a.red * a_alpha_norm + b.red * b_alpha_norm * (1.0 - a_alpha_norm)) / result->alpha;
+  result->green = (a.green * a_alpha_norm + b.green * b_alpha_norm * (1.0 - a_alpha_norm)) / result->alpha;
+  result->blue = (a.blue * a_alpha_norm + b.blue * b_alpha_norm * (1.0 - a_alpha_norm)) / result->alpha;
+
+}
+
 void
 pgtk_set_cr_source_with_color (struct frame *f, unsigned long color,
 			       bool respects_alpha_background)
@@ -7263,19 +7282,24 @@ pgtk_set_cr_source_with_color (struct frame *f, unsigned long color,
   col.pixel = color;
   pgtk_query_color (f, &col);
 
-  if (!respects_alpha_background)
-    {
-      cairo_set_source_rgb (FRAME_CR_CONTEXT (f), col.red / 65535.0,
-			    col.green / 65535.0, col.blue / 65535.0);
-      cairo_set_operator (FRAME_CR_CONTEXT (f), CAIRO_OPERATOR_OVER);
-    }
-  else
-    {
-      cairo_set_source_rgba (FRAME_CR_CONTEXT (f), col.red / 65535.0,
-			     col.green / 65535.0, col.blue / 65535.0,
-			     f->alpha_background);
-      cairo_set_operator (FRAME_CR_CONTEXT (f), CAIRO_OPERATOR_SOURCE);
-    }
+  if (respects_alpha_background) {
+    Emacs_Color frame_background;
+    pgtk_query_frame_background_color (f, &frame_background);
+
+    Emacs_Color result;
+    pgtk_cr_operator_over (col, frame_background, &result);
+
+    cairo_set_source_rgba (FRAME_CR_CONTEXT (f), result.red / 65535.0,
+			   result.green / 65535.0, result.blue / 65535.0,
+			   f->alpha_background * result.alpha);
+    cairo_set_operator (FRAME_CR_CONTEXT (f), CAIRO_OPERATOR_SOURCE);
+  } else {
+    cairo_set_source_rgba (FRAME_CR_CONTEXT (f), col.red / 65535.0,
+			   col.green / 65535.0, col.blue / 65535.0,
+			   col.alpha / 65535.0);
+    cairo_set_operator (FRAME_CR_CONTEXT (f), CAIRO_OPERATOR_OVER);
+  }
+
 }
 
 void
-- 
2.43.1


[-- Attachment #3: Emacs pgtk with face rgba support --]
[-- Type: image/png, Size: 139959 bytes --]

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

* Re: Face transparency attribute
  2024-03-17 23:02   ` Nate Sandy
@ 2024-03-18  7:41     ` Protesilaos Stavrou
  2024-03-18 13:50     ` Po Lu
  1 sibling, 0 replies; 6+ messages in thread
From: Protesilaos Stavrou @ 2024-03-18  7:41 UTC (permalink / raw)
  To: Nate Sandy, Po Lu, Sebastian Wålinder; +Cc: emacs-devel

> From: Nate Sandy <nsan@posteo.de>
> Date: Sun, 17 Mar 2024 23:02:20 +0000

> [... 24 lines elided]

> The only syntax supported for transparency is gtk_parse_rgba's
> `rgba(255,255,255,1.0)`. Maybe we would want support for `#ff00ff00` too?

Please cover this case as well. It makes it easier to tweak existing hex
values to have a transparency value than to convert them to the rgba
notation.

-- 
Protesilaos Stavrou
https://protesilaos.com



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

* Re: Face transparency attribute
  2024-03-17 23:02   ` Nate Sandy
  2024-03-18  7:41     ` Protesilaos Stavrou
@ 2024-03-18 13:50     ` Po Lu
  2024-05-03  7:01       ` Filippo Argiolas
  1 sibling, 1 reply; 6+ messages in thread
From: Po Lu @ 2024-03-18 13:50 UTC (permalink / raw)
  To: Nate Sandy; +Cc: Sebastian Wålinder, emacs-devel

Nate Sandy <nsan@posteo.de> writes:

> Po Lu <luangruo@yahoo.com> writes:
>
>> Neither approach is easy or exceptionally challenging, so interested
>> individuals are invited to chose whichever they should find more to
>> their liking.
>
> Hi Po,
>
> I have written a patch for this for the pgtk backend and went with the
> first route - supporting an alpha channel in face colors. I figured it's
> nicer since we get alpha channels for all other text decorations as
> well.
>
> The way it works is that when painting a background color (one which
> respects alpha-background), we instead compose it with the frame
> background color via a re-implementation of CAIRO_OPERATOR_OVER. I
> didn't find a way to do this with cairo itself without painting the
> surface inbetween.
>
> I also made sure that this patch integrates with alpha-background, which
> is also my primary use case - fully hiding faces which don't respect
> alpha-background.
>
> The only syntax supported for transparency is gtk_parse_rgba's
> `rgba(255,255,255,1.0)`. Maybe we would want support for `#ff00ff00` too?
>
> One interesting quirk is that when changing the opacity of the `default`
> face to less than 1, the whole background is fully transparent again. I
> am not sure whether this is a fault in my code or because of some extra
> logic regarding the `default` face.
>
> Attached are a screenshot and the patch. I'd very much appreciate
> feedback. If necessary I could also try to implement this for X and/or
> terminals, however I don't have access to other platforms.

I'm not happy with this approach, since it defines the alpha value as an
integral component of a face's foreground and background colors, rather
than an attribute (or attributes) the face merging process can manage
independently to prevent alpha values from being transferred between
faces against the user's wishes, and more broadly to enable specifying
alpha values separately from face colors, which there is plenty of
reason for users to replace that might not apply to transparency in
identical circumstances.

Furthermore, the transparency implemented in this patch is specified
with premultiplied values--premultiplied alpha is more efficient on free
systems, but admits of invalid color values whose behavior is undefined
across all the systems and toolkits we support.  It's already too easy
for Emacs users to shoot themselves in the foot, and muddling the waters
with the potential for invalid color definitions would be a step in the
wrong direction, in my humble estimation, so I would prefer an
implementation that exposes straight alpha values to users, converting
between those and the suitable alpha format for the toolkit at display
time.



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

* Re: Face transparency attribute
  2024-03-18 13:50     ` Po Lu
@ 2024-05-03  7:01       ` Filippo Argiolas
  0 siblings, 0 replies; 6+ messages in thread
From: Filippo Argiolas @ 2024-05-03  7:01 UTC (permalink / raw)
  To: Po Lu; +Cc: Nate Sandy, Sebastian Wålinder, emacs-devel

A bit late but I agree that we should have a separate attribute for this.
My use case would be to shade inactive code regions like I do in [1].

Right now I'm using a super hacky method that hooks into fontification
and adds an overlay for each symbol in the buffer with a shaded
foreground color.
With Nate's patch I would still have the very same problem. With an
attribute I could just set a single overlay over the whole inactive
region and not mess with fontification.

Is anyone still working on this? Nate?

Cheers,
Filippo

1. https://github.com/fargiolas/clangd-inactive-regions.el

On Mon, Mar 18, 2024 at 2:51 PM Po Lu <luangruo@yahoo.com> wrote:
>
> Nate Sandy <nsan@posteo.de> writes:
>
> > Po Lu <luangruo@yahoo.com> writes:
> >
> >> Neither approach is easy or exceptionally challenging, so interested
> >> individuals are invited to chose whichever they should find more to
> >> their liking.
> >
> > Hi Po,
> >
> > I have written a patch for this for the pgtk backend and went with the
> > first route - supporting an alpha channel in face colors. I figured it's
> > nicer since we get alpha channels for all other text decorations as
> > well.
> >
> > The way it works is that when painting a background color (one which
> > respects alpha-background), we instead compose it with the frame
> > background color via a re-implementation of CAIRO_OPERATOR_OVER. I
> > didn't find a way to do this with cairo itself without painting the
> > surface inbetween.
> >
> > I also made sure that this patch integrates with alpha-background, which
> > is also my primary use case - fully hiding faces which don't respect
> > alpha-background.
> >
> > The only syntax supported for transparency is gtk_parse_rgba's
> > `rgba(255,255,255,1.0)`. Maybe we would want support for `#ff00ff00` too?
> >
> > One interesting quirk is that when changing the opacity of the `default`
> > face to less than 1, the whole background is fully transparent again. I
> > am not sure whether this is a fault in my code or because of some extra
> > logic regarding the `default` face.
> >
> > Attached are a screenshot and the patch. I'd very much appreciate
> > feedback. If necessary I could also try to implement this for X and/or
> > terminals, however I don't have access to other platforms.
>
> I'm not happy with this approach, since it defines the alpha value as an
> integral component of a face's foreground and background colors, rather
> than an attribute (or attributes) the face merging process can manage
> independently to prevent alpha values from being transferred between
> faces against the user's wishes, and more broadly to enable specifying
> alpha values separately from face colors, which there is plenty of
> reason for users to replace that might not apply to transparency in
> identical circumstances.
>
> Furthermore, the transparency implemented in this patch is specified
> with premultiplied values--premultiplied alpha is more efficient on free
> systems, but admits of invalid color values whose behavior is undefined
> across all the systems and toolkits we support.  It's already too easy
> for Emacs users to shoot themselves in the foot, and muddling the waters
> with the potential for invalid color definitions would be a step in the
> wrong direction, in my humble estimation, so I would prefer an
> implementation that exposes straight alpha values to users, converting
> between those and the suitable alpha format for the toolkit at display
> time.
>



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

end of thread, other threads:[~2024-05-03  7:01 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-01-18  1:35 Face transparency attribute Sebastian Wålinder
2024-01-18  7:14 ` Po Lu
2024-03-17 23:02   ` Nate Sandy
2024-03-18  7:41     ` Protesilaos Stavrou
2024-03-18 13:50     ` Po Lu
2024-05-03  7:01       ` Filippo Argiolas

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