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.
This commit is contained in:
Jonathan Bradley 2025-05-03 18:51:46 -04:00
parent 0daa1c1fdd
commit c1640a9fda

61
dwlb.c
View File

@ -244,6 +244,7 @@ draw_text(char *text,
uint32_t x, uint32_t x,
uint32_t y, uint32_t y,
pixman_image_t *foreground, pixman_image_t *foreground,
pixman_image_t *foreground_mask,
pixman_image_t *background, pixman_image_t *background,
pixman_color_t *fg_color, pixman_color_t *fg_color,
pixman_color_t *bg_color, pixman_color_t *bg_color,
@ -265,10 +266,13 @@ draw_text(char *text,
bool draw_fg = foreground && fg_color; bool draw_fg = foreground && fg_color;
bool draw_bg = background && bg_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; pixman_color_t *cur_bg_color;
if (draw_fg) if (draw_fg) {
fg_fill = pixman_image_create_solid_fill(fg_color); cur_fg_color = fg_color;
fg_mask_fill= pixman_image_create_solid_fill(&(pixman_color_t){0xFFFF,0xFFFF,0xFFFF,0xFFFF});
}
if (draw_bg) if (draw_bg)
cur_bg_color = bg_color; cur_bg_color = bg_color;
@ -281,8 +285,7 @@ draw_text(char *text,
if (draw_bg) if (draw_bg)
cur_bg_color = &colors[color_ind].color; cur_bg_color = &colors[color_ind].color;
} else if (draw_fg) { } else if (draw_fg) {
pixman_image_unref(fg_fill); cur_fg_color = &colors[color_ind].color;
fg_fill = pixman_image_create_solid_fill(&colors[color_ind].color);
} }
color_ind++; color_ind++;
} }
@ -310,20 +313,19 @@ draw_text(char *text,
if (draw_fg) { if (draw_fg) {
/* Detect and handle pre-rendered glyphs (e.g. emoji) */ /* Detect and handle pre-rendered glyphs (e.g. emoji) */
if (pixman_image_get_format(glyph->pix) == PIXMAN_a8r8g8b8) { 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_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); x + glyph->x, y - glyph->y, glyph->width, glyph->height);
} else { } else {
/* Applying the foreground color here would mess up pixman_image_fill_boxes(PIXMAN_OP_OVER, foreground,
* component alphas for subpixel-rendered text, so we cur_fg_color, 1, &(pixman_box32_t){
* apply it when blending. */ .x1 = x, .x2 = nx,
pixman_image_composite32( .y1 = 0, .y2 = buf_height
PIXMAN_OP_OVER, fg_fill, glyph->pix, foreground, 0, 0, 0, 0, });
x + glyph->x, y - glyph->y, glyph->width, glyph->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) { if (draw_bg) {
@ -339,7 +341,7 @@ draw_text(char *text,
} }
if (draw_fg) if (draw_fg)
pixman_image_unref(fg_fill); pixman_image_unref(fg_mask_fill);
if (!last_cp) if (!last_cp)
return ix; return ix;
@ -362,7 +364,7 @@ draw_text(char *text,
} }
#define TEXT_WIDTH(text, maxwidth, padding) \ #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 static int
draw_frame(Bar *bar) draw_frame(Bar *bar)
@ -389,6 +391,7 @@ draw_frame(Bar *bar)
/* Text background and foreground layers */ /* 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 = 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); pixman_image_t *background = pixman_image_create_bits(PIXMAN_a8r8g8b8, bar->width, bar->height, NULL, bar->width * 4);
/* Draw on images */ /* Draw on images */
@ -414,6 +417,12 @@ draw_frame(Bar *bar)
.x1 = x + boxs, .x2 = x + boxs + boxw, .x1 = x + boxs, .x2 = x + boxs + boxw,
.y1 = boxs, .y2 = 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) { if ((!bar->sel || !active) && boxw >= 3) {
/* Make box hollow */ /* Make box hollow */
pixman_image_fill_boxes(PIXMAN_OP_SRC, foreground, 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, .x1 = x + boxs + 1, .x2 = x + boxs + boxw - 1,
.y1 = boxs + 1, .y2 = 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); 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, &inactive_fg_color, &inactive_bg_color, bar->width,
bar->height, bar->textpadding, NULL, 0); bar->height, bar->textpadding, NULL, 0);
uint32_t status_width = TEXT_WIDTH(bar->status.text, bar->width - x, bar->textpadding); 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, background, &inactive_fg_color, &inactive_bg_color,
bar->width, bar->height, bar->textpadding, bar->width, bar->height, bar->textpadding,
bar->status.colors, bar->status.colors_l); bar->status.colors, bar->status.colors_l);
@ -455,7 +470,7 @@ draw_frame(Bar *bar)
x = nx; x = nx;
x = draw_text(custom_title ? bar->title.text : bar->window_title, 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_fg_color : &inactive_fg_color,
(bar->sel && active_color_title) ? &active_bg_color : &inactive_bg_color, (bar->sel && active_color_title) ? &active_bg_color : &inactive_bg_color,
bar->width - status_width, bar->height, 0, bar->width - status_width, bar->height, 0,
@ -471,9 +486,11 @@ draw_frame(Bar *bar)
/* Draw background and foreground on 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, 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);
pixman_image_unref(foreground_mask);
pixman_image_unref(background); pixman_image_unref(background);
pixman_image_unref(final); pixman_image_unref(final);