aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Bradley <jcb@pikum.xyz>2025-05-03 18:51:46 -0400
committerJonathan Bradley <jcb@pikum.xyz>2025-05-04 14:58:53 -0400
commitc1640a9fda7700fa81dd57b89d874cf30aa20074 (patch)
treeebda9b7949de1c250486a373339df18000222cda
parent0daa1c1fdd82c4d790e477bf171e23ca2fdfa0cb (diff)
downloaddwlb-c1640a9fda7700fa81dd57b89d874cf30aa20074.tar.gz
blend background and foreground colors via mask
This resolves an issue when dealing with pixman where the foreground color was incorrectly handled as if already premultiplied.
-rw-r--r--dwlb.c61
1 files changed, 39 insertions, 22 deletions
diff --git a/dwlb.c b/dwlb.c
index 21b3411..faab2d9 100644
--- a/dwlb.c
+++ b/dwlb.c
@@ -244,6 +244,7 @@ draw_text(char *text,
uint32_t x,
uint32_t y,
pixman_image_t *foreground,
+ pixman_image_t *foreground_mask,
pixman_image_t *background,
pixman_color_t *fg_color,
pixman_color_t *bg_color,
@@ -265,10 +266,13 @@ draw_text(char *text,
bool draw_fg = foreground && fg_color;
bool draw_bg = background && bg_color;
- pixman_image_t *fg_fill;
+ pixman_image_t *fg_mask_fill;
+ pixman_color_t *cur_fg_color;
pixman_color_t *cur_bg_color;
- if (draw_fg)
- fg_fill = pixman_image_create_solid_fill(fg_color);
+ if (draw_fg) {
+ cur_fg_color = fg_color;
+ fg_mask_fill= pixman_image_create_solid_fill(&(pixman_color_t){0xFFFF,0xFFFF,0xFFFF,0xFFFF});
+ }
if (draw_bg)
cur_bg_color = bg_color;
@@ -281,8 +285,7 @@ draw_text(char *text,
if (draw_bg)
cur_bg_color = &colors[color_ind].color;
} else if (draw_fg) {
- pixman_image_unref(fg_fill);
- fg_fill = pixman_image_create_solid_fill(&colors[color_ind].color);
+ cur_fg_color = &colors[color_ind].color;
}
color_ind++;
}
@@ -310,20 +313,19 @@ draw_text(char *text,
if (draw_fg) {
/* Detect and handle pre-rendered glyphs (e.g. emoji) */
if (pixman_image_get_format(glyph->pix) == PIXMAN_a8r8g8b8) {
- /* Only the alpha channel of the mask is used, so we can
- * use fgfill here to blend prerendered glyphs with the
- * same opacity */
pixman_image_composite32(
- PIXMAN_OP_OVER, glyph->pix, fg_fill, foreground, 0, 0, 0, 0,
+ PIXMAN_OP_OVER, glyph->pix, NULL, foreground, 0, 0, 0, 0,
x + glyph->x, y - glyph->y, glyph->width, glyph->height);
} else {
- /* Applying the foreground color here would mess up
- * component alphas for subpixel-rendered text, so we
- * apply it when blending. */
- pixman_image_composite32(
- PIXMAN_OP_OVER, fg_fill, glyph->pix, foreground, 0, 0, 0, 0,
- x + glyph->x, y - glyph->y, glyph->width, glyph->height);
+ pixman_image_fill_boxes(PIXMAN_OP_OVER, foreground,
+ cur_fg_color, 1, &(pixman_box32_t){
+ .x1 = x, .x2 = nx,
+ .y1 = 0, .y2 = buf_height
+ });
}
+ pixman_image_composite32(
+ PIXMAN_OP_OVER, glyph->pix, fg_mask_fill, foreground_mask, 0, 0, 0, 0,
+ x + glyph->x, y - glyph->y, glyph->width, glyph->height);
}
if (draw_bg) {
@@ -339,7 +341,7 @@ draw_text(char *text,
}
if (draw_fg)
- pixman_image_unref(fg_fill);
+ pixman_image_unref(fg_mask_fill);
if (!last_cp)
return ix;
@@ -362,7 +364,7 @@ draw_text(char *text,
}
#define TEXT_WIDTH(text, maxwidth, padding) \
- draw_text(text, 0, 0, NULL, NULL, NULL, NULL, maxwidth, 0, padding, NULL, 0)
+ draw_text(text, 0, 0, NULL, NULL, NULL, NULL, NULL, maxwidth, 0, padding, NULL, 0)
static int
draw_frame(Bar *bar)
@@ -389,6 +391,7 @@ draw_frame(Bar *bar)
/* Text background and foreground layers */
pixman_image_t *foreground = pixman_image_create_bits(PIXMAN_a8r8g8b8, bar->width, bar->height, NULL, bar->width * 4);
+ pixman_image_t *foreground_mask = pixman_image_create_bits(PIXMAN_a8, bar->width, bar->height, NULL, bar->width * 4);
pixman_image_t *background = pixman_image_create_bits(PIXMAN_a8r8g8b8, bar->width, bar->height, NULL, bar->width * 4);
/* Draw on images */
@@ -414,6 +417,12 @@ draw_frame(Bar *bar)
.x1 = x + boxs, .x2 = x + boxs + boxw,
.y1 = boxs, .y2 = boxs + boxw
});
+ pixman_image_fill_boxes(PIXMAN_OP_SRC, foreground_mask,
+ &(pixman_color_t){0xFFFF,0xFFFF,0xFFFF,0xFFFF},
+ 1, &(pixman_box32_t){
+ .x1 = x + boxs, .x2 = x + boxs + boxw,
+ .y1 = boxs, .y2 = boxs + boxw
+ });
if ((!bar->sel || !active) && boxw >= 3) {
/* Make box hollow */
pixman_image_fill_boxes(PIXMAN_OP_SRC, foreground,
@@ -422,19 +431,25 @@ draw_frame(Bar *bar)
.x1 = x + boxs + 1, .x2 = x + boxs + boxw - 1,
.y1 = boxs + 1, .y2 = boxs + boxw - 1
});
+ pixman_image_fill_boxes(PIXMAN_OP_SRC, foreground_mask,
+ &(pixman_color_t){ 0 },
+ 1, &(pixman_box32_t){
+ .x1 = x + boxs + 1, .x2 = x + boxs + boxw - 1,
+ .y1 = boxs + 1, .y2 = boxs + boxw - 1
+ });
}
}
- x = draw_text(tags[i], x, y, foreground, background, fg_color, bg_color,
+ x = draw_text(tags[i], x, y, foreground, foreground_mask, background, fg_color, bg_color,
bar->width, bar->height, bar->textpadding, NULL, 0);
}
- x = draw_text(bar->layout, x, y, foreground, background,
+ x = draw_text(bar->layout, x, y, foreground, foreground_mask, background,
&inactive_fg_color, &inactive_bg_color, bar->width,
bar->height, bar->textpadding, NULL, 0);
uint32_t status_width = TEXT_WIDTH(bar->status.text, bar->width - x, bar->textpadding);
- draw_text(bar->status.text, bar->width - status_width, y, foreground,
+ draw_text(bar->status.text, bar->width - status_width, y, foreground, foreground_mask,
background, &inactive_fg_color, &inactive_bg_color,
bar->width, bar->height, bar->textpadding,
bar->status.colors, bar->status.colors_l);
@@ -455,7 +470,7 @@ draw_frame(Bar *bar)
x = nx;
x = draw_text(custom_title ? bar->title.text : bar->window_title,
- x, y, foreground, background,
+ x, y, foreground, foreground_mask, background,
(bar->sel && active_color_title) ? &active_fg_color : &inactive_fg_color,
(bar->sel && active_color_title) ? &active_bg_color : &inactive_bg_color,
bar->width - status_width, bar->height, 0,
@@ -471,9 +486,11 @@ draw_frame(Bar *bar)
/* Draw background and foreground on bar */
pixman_image_composite32(PIXMAN_OP_OVER, background, NULL, final, 0, 0, 0, 0, 0, 0, bar->width, bar->height);
- pixman_image_composite32(PIXMAN_OP_OVER, foreground, NULL, final, 0, 0, 0, 0, 0, 0, bar->width, bar->height);
+ pixman_image_set_alpha_map(foreground, foreground_mask, 0, 0);
+ pixman_image_composite32(PIXMAN_OP_OVER, foreground, foreground_mask, final, 0, 0, 0, 0, 0, 0, bar->width, bar->height);
pixman_image_unref(foreground);
+ pixman_image_unref(foreground_mask);
pixman_image_unref(background);
pixman_image_unref(final);