diff --git a/render.c b/render.c index fdaaf85d..1b71137b 100644 --- a/render.c +++ b/render.c @@ -404,7 +404,7 @@ render_cell(struct terminal *term, pixman_image_t *pix, struct font *font = attrs_to_font(term, &cell->attrs); const struct glyph *glyph = cell->wc != 0 - ? font_glyph_for_wc(font, cell->wc, term->colors.alpha == 0xffff) + ? font_glyph_for_wc(font, cell->wc, term->font_subpixel) : NULL; int cell_cols = glyph != NULL ? max(1, glyph->cols) : 1; diff --git a/terminal.c b/terminal.c index 44234007..f3d50989 100644 --- a/terminal.c +++ b/terminal.c @@ -579,6 +579,50 @@ get_font_dpi(const struct terminal *term) return dpi; } +static enum subpixel_order +get_font_subpixel(const struct terminal *term) +{ + if (term->colors.alpha != 0xffff) { + /* Can't do subpixel rendering on transparent background */ + return FCFT_SUBPIXEL_ORDER_NONE; + } + + enum wl_output_subpixel wl_subpixel; + + /* + * Wayland doesn't tell us *which* part of the surface that goes + * on a specific output, only whether the surface is mapped to an + * output or not. + * + * Thus, when determining which subpixel mode to use, we can't do + * much but select *an* output. So, we pick the first one. + * + * If we're not mapped at all, we pick the first available + * monitor, and hope that's where we'll eventually get mapped. + * + * If there aren't any monitors we use the "default" subpixel + * mode. + */ + + if (tll_length(term->window->on_outputs) > 0) + wl_subpixel = tll_front(term->window->on_outputs)->subpixel; + else if (tll_length(term->wl->monitors) > 0) + wl_subpixel = tll_front(term->wl->monitors).subpixel; + else + wl_subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN; + + switch (wl_subpixel) { + case WL_OUTPUT_SUBPIXEL_UNKNOWN: return FCFT_SUBPIXEL_ORDER_DEFAULT; + case WL_OUTPUT_SUBPIXEL_NONE: return FCFT_SUBPIXEL_ORDER_NONE; + case WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB: return FCFT_SUBPIXEL_ORDER_HORIZONTAL_RGB; + case WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR: return FCFT_SUBPIXEL_ORDER_HORIZONTAL_BGR; + case WL_OUTPUT_SUBPIXEL_VERTICAL_RGB: return FCFT_SUBPIXEL_ORDER_VERTICAL_RGB; + case WL_OUTPUT_SUBPIXEL_VERTICAL_BGR: return FCFT_SUBPIXEL_ORDER_VERTICAL_BGR; + } + + return FCFT_SUBPIXEL_ORDER_DEFAULT; +} + static bool load_fonts_from_conf(const struct terminal *term, const struct config *conf, struct font *fonts[static 4]) @@ -686,6 +730,9 @@ term_init(const struct config *conf, struct fdm *fdm, struct wayland *wayl, .ptmx_buffer = tll_init(), .font_dpi = 0, .font_adjustments = 0, + .font_subpixel = (conf->colors.alpha == 0xffff /* Can't do subpixel rendering on transparent background */ + ? FCFT_SUBPIXEL_ORDER_DEFAULT + : FCFT_SUBPIXEL_ORDER_NONE), .cursor_keys_mode = CURSOR_KEYS_NORMAL, .keypad_keys_mode = KEYPAD_NUMERICAL, .auto_margin = true, @@ -1331,6 +1378,31 @@ term_font_dpi_changed(struct terminal *term) return false; } +void +term_font_subpixel_changed(struct terminal *term) +{ + enum subpixel_order subpixel = get_font_subpixel(term); + + if (term->font_subpixel == subpixel) + return; + +#if defined(_DEBUG) && LOG_ENABLE_DBG + static const char *const str[] = { + [FCFT_SUBPIXEL_ORDER_DEFAULT] = "default", + [FCFT_SUBPIXEL_ORDER_NONE] = "disabled", + [FCFT_SUBPIXEL_ORDER_HORIZONTAL_RGB] = "RGB", + [FCFT_SUBPIXEL_ORDER_HORIZONTAL_BGR] = "BGR", + [FCFT_SUBPIXEL_ORDER_VERTICAL_RGB] = "V-RGB", + [FCFT_SUBPIXEL_ORDER_VERTICAL_BGR] = "V-BGR", + }; +#endif + + LOG_DBG("subpixel mode changed: %s -> %s", str[term->font_subpixel], str[subpixel]); + term->font_subpixel = subpixel; + term_damage_view(term); + render_refresh(term); +} + void term_damage_rows(struct terminal *term, int start, int end) { diff --git a/terminal.h b/terminal.h index 7b7b0182..0ef3db75 100644 --- a/terminal.h +++ b/terminal.h @@ -217,6 +217,7 @@ struct terminal { struct font *fonts[4]; int font_dpi; int font_adjustments; + enum subpixel_order font_subpixel; tll(struct ptmx_buffer) ptmx_buffer; @@ -445,6 +446,8 @@ bool term_font_size_increase(struct terminal *term); bool term_font_size_decrease(struct terminal *term); bool term_font_size_reset(struct terminal *term); bool term_font_dpi_changed(struct terminal *term); +void term_font_subpixel_changed(struct terminal *term); + void term_damage_rows(struct terminal *term, int start, int end); void term_damage_rows_in_view(struct terminal *term, int start, int end); diff --git a/wayland.c b/wayland.c index 06c02313..b0a5cfc3 100644 --- a/wayland.c +++ b/wayland.c @@ -146,6 +146,7 @@ update_term_for_output_change(struct terminal *term) render_resize(term, term->width / term->scale, term->height / term->scale); term_font_dpi_changed(term); + term_font_subpixel_changed(term); wayl_reload_cursor_theme(term->wl, term); } @@ -193,6 +194,7 @@ output_geometry(void *data, struct wl_output *wl_output, int32_t x, int32_t y, mon->inch = sqrt(pow(mon->dim.mm.width, 2) + pow(mon->dim.mm.height, 2)) * 0.03937008; mon->make = make != NULL ? strdup(make) : NULL; mon->model = model != NULL ? strdup(model) : NULL; + mon->subpixel = subpixel; output_update_ppi(mon); } diff --git a/wayland.h b/wayland.h index e2abae72..a550b247 100644 --- a/wayland.h +++ b/wayland.h @@ -60,6 +60,7 @@ struct monitor { int scale; float refresh; + enum wl_output_subpixel subpixel; char *make; char *model;