summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/config.c120
-rw-r--r--src/entry.c16
-rw-r--r--src/entry_backend/harfbuzz.c55
-rw-r--r--src/entry_backend/harfbuzz.h3
-rw-r--r--src/main.c31
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;
};
diff --git a/src/main.c b/src/main.c
index dbfb718..04e8529 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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");