diff options
-rw-r--r-- | src/config.c | 120 | ||||
-rw-r--r-- | src/entry.c | 16 | ||||
-rw-r--r-- | src/entry_backend/harfbuzz.c | 55 | ||||
-rw-r--r-- | src/entry_backend/harfbuzz.h | 3 | ||||
-rw-r--r-- | src/main.c | 31 |
5 files changed, 96 insertions, 129 deletions
diff --git a/src/config.c b/src/config.c index ab1e4e3..23dbc7f 100644 --- a/src/config.c +++ b/src/config.c @@ -74,8 +74,7 @@ struct uint32_percent { static char *strip(const char *str); static bool parse_option(struct tofi *tofi, const char *filename, size_t lineno, const char *option, const char *value); static char *get_config_path(void); -static uint32_t fixup_percentage(uint32_t value, uint32_t base, bool is_percent, uint32_t scale, bool use_scale); -static void fixup_text_theme(struct text_theme *theme, uint32_t scale); +static uint32_t fixup_percentage(uint32_t value, uint32_t base, bool is_percent); static uint32_t parse_anchor(const char *filename, size_t lineno, const char *str, bool *err); static enum cursor_style parse_cursor_style(const char *filename, size_t lineno, const char *str, bool *err); @@ -753,112 +752,69 @@ bool config_apply(struct tofi *tofi, const char *option, const char *value) return parse_option(tofi, "", 0, option, value); } -uint32_t fixup_percentage(uint32_t value, uint32_t base, bool is_percent, uint32_t scale, bool use_scale) +uint32_t fixup_percentage(uint32_t value, uint32_t base, bool is_percent) { if (is_percent) { return value * base / 100; - } else if (use_scale) { - return value * scale; } return value; } -void fixup_text_theme(struct text_theme *theme, uint32_t scale) -{ - theme->background_corner_radius *= scale; - theme->padding.top *= scale; - theme->padding.bottom *= scale; - theme->padding.left *= scale; - theme->padding.right *= scale; -} - void config_fixup_values(struct tofi *tofi) { uint32_t scale = tofi->window.scale; + uint32_t base_width = tofi->output_width; + uint32_t base_height = tofi->output_height; + /* + * If we're going to be scaling these values in Cairo, + * we need to apply the inverse scale here. + */ if (tofi->use_scale) { - struct entry *entry = &tofi->window.entry; - - entry->font_size *= scale; - entry->prompt_padding *= scale; - entry->corner_radius *= scale; - entry->result_spacing *= scale; - entry->input_width *= scale; - entry->outline_width *= scale; - entry->border_width *= scale; - - entry->cursor_theme.corner_radius *= scale; - entry->cursor_theme.thickness *= scale; - - fixup_text_theme(&entry->prompt_theme, scale); - fixup_text_theme(&entry->placeholder_theme, scale); - fixup_text_theme(&entry->input_theme, scale); - fixup_text_theme(&entry->default_result_theme, scale); - fixup_text_theme(&entry->alternate_result_theme, scale); - fixup_text_theme(&entry->selection_theme, scale); + base_width /= scale; + base_height /= scale; } - /* These values should only be scaled if they're not percentages. */ tofi->window.width = fixup_percentage( tofi->window.width, - tofi->output_width, - tofi->window.width_is_percent, - tofi->window.scale, - tofi->use_scale); + base_width, + tofi->window.width_is_percent); tofi->window.height = fixup_percentage( tofi->window.height, - tofi->output_height, - tofi->window.height_is_percent, - tofi->window.scale, - tofi->use_scale); + base_height, + tofi->window.height_is_percent); tofi->window.margin_top = fixup_percentage( tofi->window.margin_top, - tofi->output_height, - tofi->window.margin_top_is_percent, - tofi->window.scale, - tofi->use_scale); + base_height, + tofi->window.margin_top_is_percent); tofi->window.margin_bottom = fixup_percentage( tofi->window.margin_bottom, - tofi->output_height, - tofi->window.margin_bottom_is_percent, - tofi->window.scale, - tofi->use_scale); + base_height, + tofi->window.margin_bottom_is_percent); tofi->window.margin_left = fixup_percentage( tofi->window.margin_left, - tofi->output_width, - tofi->window.margin_left_is_percent, - tofi->window.scale, - tofi->use_scale); + base_width, + tofi->window.margin_left_is_percent); tofi->window.margin_right = fixup_percentage( tofi->window.margin_right, - tofi->output_width, - tofi->window.margin_right_is_percent, - tofi->window.scale, - tofi->use_scale); + base_width, + tofi->window.margin_right_is_percent); tofi->window.entry.padding_top = fixup_percentage( tofi->window.entry.padding_top, - tofi->output_height, - tofi->window.entry.padding_top_is_percent, - tofi->window.scale, - tofi->use_scale); + base_height, + tofi->window.entry.padding_top_is_percent); tofi->window.entry.padding_bottom = fixup_percentage( tofi->window.entry.padding_bottom, - tofi->output_height, - tofi->window.entry.padding_bottom_is_percent, - tofi->window.scale, - tofi->use_scale); + base_height, + tofi->window.entry.padding_bottom_is_percent); tofi->window.entry.padding_left = fixup_percentage( tofi->window.entry.padding_left, - tofi->output_width, - tofi->window.entry.padding_left_is_percent, - tofi->window.scale, - tofi->use_scale); + base_width, + tofi->window.entry.padding_left_is_percent); tofi->window.entry.padding_right = fixup_percentage( tofi->window.entry.padding_right, - tofi->output_width, - tofi->window.entry.padding_right_is_percent, - tofi->window.scale, - tofi->use_scale); + base_width, + tofi->window.entry.padding_right_is_percent); /* Don't attempt percentage handling if exclusive_zone is set to -1. */ if (tofi->window.exclusive_zone > 0) { @@ -868,24 +824,20 @@ void config_fixup_values(struct tofi *tofi) case ANCHOR_BOTTOM: tofi->window.exclusive_zone = fixup_percentage( tofi->window.exclusive_zone, - tofi->output_height, - tofi->window.exclusive_zone_is_percent, - tofi->window.scale, - tofi->use_scale); + base_height, + tofi->window.exclusive_zone_is_percent); break; case ANCHOR_LEFT: case ANCHOR_RIGHT: tofi->window.exclusive_zone = fixup_percentage( tofi->window.exclusive_zone, - tofi->output_width, - tofi->window.exclusive_zone_is_percent, - tofi->window.scale, - tofi->use_scale); + base_width, + tofi->window.exclusive_zone_is_percent); break; default: /* - * Exclusive zone >0 is meaningless for other anchor - * positions. + * Exclusive zone >0 is meaningless for other + * anchor positions. */ tofi->window.exclusive_zone = MIN(tofi->window.exclusive_zone, 0); diff --git a/src/entry.c b/src/entry.c index 6a55741..4ad825a 100644 --- a/src/entry.c +++ b/src/entry.c @@ -64,6 +64,7 @@ void entry_init(struct entry *entry, uint8_t *restrict buffer, uint32_t width, u height, width * sizeof(uint32_t) ); + cairo_surface_set_device_scale(surface, scale, scale); cairo_t *cr = cairo_create(surface); entry->cairo[0].surface = surface; @@ -76,8 +77,12 @@ void entry_init(struct entry *entry, uint8_t *restrict buffer, uint32_t width, u height, width * sizeof(uint32_t) ); + cairo_surface_set_device_scale(entry->cairo[1].surface, scale, scale); entry->cairo[1].cr = cairo_create(entry->cairo[1].surface); + /* If we're scaling with Cairo, remember to account for that here. */ + width /= scale; + height /= scale; log_debug("Drawing window.\n"); /* Draw the background */ @@ -197,17 +202,6 @@ void entry_init(struct entry *entry, uint8_t *restrict buffer, uint32_t width, u } /* - * TODO: - * This is a dirty hack. The proper thing to do is probably just to - * stop scaling everything manually, set cairo_scale and have done - * with. The reason that isn't how things are currently done is due to - * historic scaling behaviour of tofi. - */ - if (!entry->cursor_theme.thickness_specified) { - entry->cursor_theme.thickness *= scale; - } - - /* * Perform an initial render of the text. * This is done here rather than by calling entry_update to avoid the * unnecessary cairo_paint() of the background for the first frame, diff --git a/src/entry_backend/harfbuzz.c b/src/entry_backend/harfbuzz.c index ae26d67..3bb8a8f 100644 --- a/src/entry_backend/harfbuzz.c +++ b/src/entry_backend/harfbuzz.c @@ -84,7 +84,7 @@ static void setup_hb_buffer(hb_buffer_t *buffer) * Render a hb_buffer with Cairo, and return the extents of the rendered text * in Cairo units. */ -static cairo_text_extents_t render_hb_buffer(cairo_t *cr, hb_buffer_t *buffer) +static cairo_text_extents_t render_hb_buffer(cairo_t *cr, hb_font_extents_t *font_extents, hb_buffer_t *buffer, double scale) { cairo_save(cr); @@ -92,9 +92,7 @@ static cairo_text_extents_t render_hb_buffer(cairo_t *cr, hb_buffer_t *buffer) * Cairo uses y-down coordinates, but HarfBuzz uses y-up, so we * shift the text down by its ascent height to compensate. */ - cairo_font_extents_t font_extents; - cairo_font_extents(cr, &font_extents); - cairo_translate(cr, 0, font_extents.ascent); + cairo_translate(cr, 0, font_extents->ascender / 64.0); unsigned int glyph_count; hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(buffer, &glyph_count); @@ -107,12 +105,17 @@ static cairo_text_extents_t render_hb_buffer(cairo_t *cr, hb_buffer_t *buffer) /* * The coordinates returned by HarfBuzz are in 26.6 fixed-point * format, so we divide by 64.0 (2^6) to get floats. + * + * For whatever reason, the coordinates are also scaled by + * Cairo's scale factor, so we have to also divide by the scale + * factor to account for this. */ cairo_glyphs[i].index = glyph_info[i].codepoint; - cairo_glyphs[i].x = x + glyph_pos[i].x_offset / 64.0; - cairo_glyphs[i].y = y - glyph_pos[i].y_offset / 64.0; - x += glyph_pos[i].x_advance / 64.0; - y -= glyph_pos[i].y_advance / 64.0; + cairo_glyphs[i].x = x + glyph_pos[i].x_offset / 64.0 / scale; + cairo_glyphs[i].y = y - glyph_pos[i].y_offset / 64.0 / scale; + + x += glyph_pos[i].x_advance / 64.0 / scale; + y -= glyph_pos[i].y_advance / 64.0 / scale; } cairo_show_glyphs(cr, cairo_glyphs, glyph_count); @@ -121,7 +124,7 @@ static cairo_text_extents_t render_hb_buffer(cairo_t *cr, hb_buffer_t *buffer) cairo_glyph_extents(cr, cairo_glyphs, glyph_count, &extents); /* Account for the shifted baseline in our returned text extents. */ - extents.y_bearing += font_extents.ascent; + extents.y_bearing += font_extents->ascender / 64.0; free(cairo_glyphs); @@ -143,7 +146,7 @@ static cairo_text_extents_t render_text( setup_hb_buffer(hb->hb_buffer); hb_buffer_add_utf8(hb->hb_buffer, text, -1, 0, -1); hb_shape(hb->hb_font, hb->hb_buffer, hb->hb_features, hb->num_features); - return render_hb_buffer(cr, hb->hb_buffer); + return render_hb_buffer(cr, &hb->hb_font_extents, hb->hb_buffer, hb->scale); } @@ -259,7 +262,7 @@ static cairo_text_extents_t render_input( setup_hb_buffer(hb->hb_buffer); hb_buffer_add_utf32(hb->hb_buffer, text, -1, 0, -1); hb_shape(hb->hb_font, hb->hb_buffer, hb->hb_features, hb->num_features); - cairo_text_extents_t extents = render_hb_buffer(cr, hb->hb_buffer); + cairo_text_extents_t extents = render_hb_buffer(cr, &hb->hb_font_extents, hb->hb_buffer, hb->scale); /* * If the cursor is at the end of text, we need to account for it in @@ -304,7 +307,7 @@ static cairo_text_extents_t render_input( color = theme->foreground_color; cairo_set_source_rgba(cr, color.r, color.g, color.b, color.a); - render_hb_buffer(cr, hb->hb_buffer); + render_hb_buffer(cr, &hb->hb_font_extents, hb->hb_buffer, hb->scale); } if (!cursor_theme->show) { @@ -385,8 +388,8 @@ static cairo_text_extents_t render_input( cursor_end += x_advance; } /* Convert from HarfBuzz 26.6 fixed-point to float. */ - cursor_x = cursor_start / 64.0; - cursor_width = (cursor_end - cursor_start) / 64.0; + cursor_x = cursor_start / 64.0 / hb->scale; + cursor_width = (cursor_end - cursor_start) / 64.0 / hb->scale; } cairo_save(cr); @@ -405,7 +408,7 @@ static cairo_text_extents_t render_input( cairo_translate(cr, -cursor_x, 0); color = cursor_theme->text_color; cairo_set_source_rgba(cr, color.r, color.g, color.b, color.a); - render_hb_buffer(cr, hb->hb_buffer); + render_hb_buffer(cr, &hb->hb_font_extents, hb->hb_buffer, hb->scale); break; case CURSOR_STYLE_UNDERSCORE: cairo_translate(cr, 0, cursor_theme->underline_depth); @@ -444,6 +447,7 @@ void entry_backend_harfbuzz_init( struct entry_backend_harfbuzz *hb = &entry->harfbuzz; cairo_t *cr = entry->cairo[0].cr; uint32_t font_size = floor(entry->font_size * PT_TO_DPI); + cairo_surface_get_device_scale(entry->cairo[0].surface, &hb->scale, NULL); /* * Setting up our font has three main steps: @@ -582,6 +586,11 @@ void entry_backend_harfbuzz_init( log_debug("Creating Harfbuzz buffer.\n"); hb->hb_buffer = hb_buffer_create(); + hb_font_get_h_extents(hb->hb_font, &hb->hb_font_extents); + if (hb->hb_font_extents.line_gap == 0) { + hb->hb_font_extents.line_gap = (hb->hb_font_extents.ascender - hb->hb_font_extents.descender); + } + log_debug("Creating Cairo font.\n"); hb->cairo_face = cairo_ft_font_face_create_for_ft_face(hb->ft_face, 0); @@ -619,13 +628,17 @@ void entry_backend_harfbuzz_update(struct entry *entry) cairo_t *cr = entry->cairo[entry->index].cr; cairo_text_extents_t extents; - cairo_font_extents_t font_extents; - cairo_font_extents(cr, &font_extents); - cairo_save(cr); /* Render the prompt */ extents = render_text_themed(cr, entry, entry->prompt_text, &entry->prompt_theme); + { + struct entry_backend_harfbuzz *hb = &entry->harfbuzz; + hb_buffer_clear_contents(hb->hb_buffer); + setup_hb_buffer(hb->hb_buffer); + hb_buffer_add_utf8(hb->hb_buffer, "test", -1, 0, -1); + hb_shape(hb->hb_font, hb->hb_buffer, hb->hb_features, hb->num_features); + } cairo_translate(cr, extents.x_advance, 0); cairo_translate(cr, entry->prompt_padding, 0); @@ -683,7 +696,7 @@ void entry_backend_harfbuzz_update(struct entry *entry) if (entry->horizontal) { cairo_translate(cr, extents.x_advance + entry->result_spacing, 0); } else { - cairo_translate(cr, 0, font_extents.height + entry->result_spacing); + cairo_translate(cr, 0, entry->harfbuzz.hb_font_extents.line_gap / 64.0 + entry->result_spacing); } if (entry->num_results == 0) { if (size_overflows(entry, 0, 0)) { @@ -729,7 +742,7 @@ void entry_backend_harfbuzz_update(struct entry *entry) * The height of the text doesn't change, so * we don't need to re-measure it each time. */ - if (size_overflows(entry, 0, font_extents.height)) { + if (size_overflows(entry, 0, entry->harfbuzz.hb_font_extents.line_gap / 64.0)) { break; } else { extents = render_text_themed(cr, entry, result, theme); @@ -871,7 +884,7 @@ void entry_backend_harfbuzz_update(struct entry *entry) rounded_rectangle( cr, ceil(extents.width + padding.left + padding.right), - ceil(font_extents.height + padding.top + padding.bottom), + ceil(entry->harfbuzz.hb_font_extents.line_gap / 64.0 + padding.top + padding.bottom), entry->selection_theme.background_corner_radius ); cairo_fill(cr); diff --git a/src/entry_backend/harfbuzz.h b/src/entry_backend/harfbuzz.h index 17b5945..acaa2eb 100644 --- a/src/entry_backend/harfbuzz.h +++ b/src/entry_backend/harfbuzz.h @@ -19,12 +19,15 @@ struct entry_backend_harfbuzz { cairo_font_face_t *cairo_face; hb_font_t *hb_font; + hb_font_extents_t hb_font_extents; hb_buffer_t *hb_buffer; hb_variation_t hb_variations[MAX_FONT_VARIATIONS]; hb_feature_t hb_features[MAX_FONT_FEATURES]; uint8_t num_variations; uint8_t num_features; + double scale; + bool disable_hinting; }; @@ -104,11 +104,11 @@ static void zwlr_layer_surface_configure( * We want actual pixel width / height, so we have to scale the * values provided by Wayland. */ - tofi->window.width = width * tofi->window.scale; - tofi->window.height = height * tofi->window.scale; + tofi->window.width = width; + tofi->window.height = height; - tofi->window.surface.width = tofi->window.width; - tofi->window.surface.height = tofi->window.height; + tofi->window.surface.width = width * tofi->window.scale; + tofi->window.surface.height = height * tofi->window.scale; zwlr_layer_surface_v1_ack_configure( tofi->window.zwlr_layer_surface, @@ -1462,16 +1462,21 @@ int main(int argc, char *argv[]) zwlr_layer_surface_v1_set_exclusive_zone( tofi.window.zwlr_layer_surface, tofi.window.exclusive_zone); + /* + * No matter whether we're scaling via Cairo or not, we're presenting a + * scaled buffer to Wayland, so scale the window size here if we + * haven't already done so. + */ zwlr_layer_surface_v1_set_size( tofi.window.zwlr_layer_surface, - tofi.window.width / tofi.window.scale, - tofi.window.height / tofi.window.scale); + tofi.window.width / (tofi.use_scale ? 1 : tofi.window.scale), + tofi.window.height / (tofi.use_scale ? 1 : tofi.window.scale)); zwlr_layer_surface_v1_set_margin( tofi.window.zwlr_layer_surface, - tofi.window.margin_top / tofi.window.scale, - tofi.window.margin_right / tofi.window.scale, - tofi.window.margin_bottom / tofi.window.scale, - tofi.window.margin_left / tofi.window.scale); + tofi.window.margin_top, + tofi.window.margin_right, + tofi.window.margin_bottom, + tofi.window.margin_left); wl_surface_commit(tofi.window.surface.wl_surface); /* @@ -1524,8 +1529,8 @@ int main(int argc, char *argv[]) entry_init( &tofi.window.entry, tofi.window.surface.shm_pool_data, - tofi.window.width, - tofi.window.height, + tofi.window.surface.width, + tofi.window.surface.height, tofi.use_scale ? tofi.window.scale : 1); log_unindent(); log_debug("Renderer initialised.\n"); @@ -1546,7 +1551,7 @@ int main(int argc, char *argv[]) memcpy( cairo_image_surface_get_data(tofi.window.entry.cairo[1].surface), cairo_image_surface_get_data(tofi.window.entry.cairo[0].surface), - tofi.window.entry.image.width * tofi.window.entry.image.height * sizeof(uint32_t) + tofi.window.surface.width * tofi.window.surface.height * sizeof(uint32_t) ); log_debug("Second buffer initialised.\n"); |