summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--completions/tofi3
-rw-r--r--doc/config12
-rw-r--r--doc/tofi.5.md9
-rw-r--r--doc/tofi.5.scd8
-rw-r--r--meson.build7
-rw-r--r--src/config.c2
-rw-r--r--src/entry.c1
-rw-r--r--src/entry.h4
-rw-r--r--src/entry_backend/harfbuzz.c83
-rw-r--r--src/entry_backend/harfbuzz.h3
-rw-r--r--src/entry_backend/pango.c5
-rw-r--r--src/main.c8
12 files changed, 120 insertions, 25 deletions
diff --git a/completions/tofi b/completions/tofi
index ca19509..0e50af2 100644
--- a/completions/tofi
+++ b/completions/tofi
@@ -16,6 +16,8 @@ _tofi()
--corner-radius
--font
--font-size
+ --font-features
+ --font-variations
--num-results
--selection-color
--selection-match-color
@@ -54,7 +56,6 @@ _tofi()
--drun-launch
--terminal
--hint-font
- --font-features
--late-keyboard-init
--multi-instance
)
diff --git a/doc/config b/doc/config
index ae1e653..3e28eac 100644
--- a/doc/config
+++ b/doc/config
@@ -25,9 +25,19 @@
# Examples:
#
# font-features = "smcp, c2sc" (all small caps)
- # font-features = "liga 0" (disable ligatures
+ # font-features = "liga 0" (disable ligatures)
font-features = ""
+ # Comma separated list of OpenType font variation settings to apply
+ # to variable fonts. The format is similar to the CSS
+ # "font-variation-settings" property.
+ #
+ # Examples:
+ #
+ # font-variations = "wght 900" (Extra bold)
+ # font-variations = "wdth 25, slnt -10" (Narrow and slanted)
+ font-variations = ""
+
# Perform font hinting. Only applies when a path to a font has been
# specified via `font`. Disabling font hinting speeds up text
# rendering appreciably, but will likely look poor at small font pixel
diff --git a/doc/tofi.5.md b/doc/tofi.5.md
index dea750c..e5f947b 100644
--- a/doc/tofi.5.md
+++ b/doc/tofi.5.md
@@ -165,6 +165,15 @@ options.
>
> Default: ""
+**font-variations**=*variations*
+
+> Comma separated list of OpenType font variation settings to apply. The
+> format is similar to the CSS "font-variation-settings" property. For
+> example, "wght 900" will set the weight of a variable font to 900 (if
+> supported by the chosen font).
+>
+> Default: ""
+
**background-color**=*color*
> Color of the background. See **COLORS** for more information.
diff --git a/doc/tofi.5.scd b/doc/tofi.5.scd
index 9ff7f3d..acdb16a 100644
--- a/doc/tofi.5.scd
+++ b/doc/tofi.5.scd
@@ -143,6 +143,14 @@ options.
Default: ""
+*font-variations*=_variations_
+ Comma separated list of OpenType font variation settings to apply. The
+ format is similar to the CSS "font-variation-settings" property. For
+ example, "wght 900" will set the weight of a variable font to 900 (if
+ supported by the chosen font).
+
+ Default: ""
+
*background-color*=_color_
Color of the background. See *COLORS* for more information.
diff --git a/meson.build b/meson.build
index 3071aed..ae49ba5 100644
--- a/meson.build
+++ b/meson.build
@@ -147,6 +147,13 @@ if wayland_client.version().version_compare('<1.20.0')
)
endif
+if harfbuzz.version().version_compare('<4.4.0')
+ add_project_arguments(
+ ['-DNO_HARFBUZZ_FONT_CHANGED=1'],
+ language: 'c'
+ )
+endif
+
# Generate the necessary Wayland headers / sources with wayland-scanner
diff --git a/src/config.c b/src/config.c
index 6655f00..3a65d3d 100644
--- a/src/config.c
+++ b/src/config.c
@@ -327,6 +327,8 @@ bool parse_option(struct tofi *tofi, const char *filename, size_t lineno, const
tofi->window.entry.font_size = parse_uint32(filename, lineno, value, &err);
} else if (strcasecmp(option, "font-features") == 0) {
snprintf(tofi->window.entry.font_features, N_ELEM(tofi->window.entry.font_features), "%s", value);
+ } else if (strcasecmp(option, "font-variations") == 0) {
+ snprintf(tofi->window.entry.font_variations, N_ELEM(tofi->window.entry.font_variations), "%s", value);
} else if (strcasecmp(option, "num-results") == 0) {
tofi->window.entry.num_results = parse_uint32(filename, lineno, value, &err);
} else if (strcasecmp(option, "outline-width") == 0) {
diff --git a/src/entry.c b/src/entry.c
index 3d0c284..70f4525 100644
--- a/src/entry.c
+++ b/src/entry.c
@@ -63,6 +63,7 @@ void entry_init(struct entry *entry, uint8_t *restrict buffer, uint32_t width, u
entry->cairo[1].cr = cairo_create(entry->cairo[1].surface);
+ log_debug("Drawing window.\n");
/* Draw the background */
struct color color = entry->background_color;
cairo_set_source_rgba(cr, color.r, color.g, color.b, color.a);
diff --git a/src/entry.h b/src/entry.h
index fb8e6c7..8e9d2b4 100644
--- a/src/entry.h
+++ b/src/entry.h
@@ -16,7 +16,8 @@
#define MAX_INPUT_LENGTH 256
#define MAX_PROMPT_LENGTH 256
#define MAX_FONT_NAME_LENGTH 256
-#define MAX_FONT_FEATURES_LENGTH 256
+#define MAX_FONT_FEATURES_LENGTH 128
+#define MAX_FONT_VARIATIONS_LENGTH 128
struct entry {
struct image image;
@@ -59,6 +60,7 @@ struct entry {
uint32_t font_size;
char font_name[MAX_FONT_NAME_LENGTH];
char font_features[MAX_FONT_FEATURES_LENGTH];
+ char font_variations[MAX_FONT_VARIATIONS_LENGTH];
char prompt_text[MAX_PROMPT_LENGTH];
char placeholder_text[MAX_PROMPT_LENGTH];
uint32_t prompt_padding;
diff --git a/src/entry_backend/harfbuzz.c b/src/entry_backend/harfbuzz.c
index 53b1740..f038578 100644
--- a/src/entry_backend/harfbuzz.c
+++ b/src/entry_backend/harfbuzz.c
@@ -147,6 +147,23 @@ void entry_backend_harfbuzz_init(
cairo_t *cr = entry->cairo[0].cr;
uint32_t font_size = floor(entry->font_size * PT_TO_DPI);
+ /*
+ * Setting up our font has three main steps:
+ *
+ * 1. Load the font face with FreeType.
+ * 2. Create a HarfBuzz font referencing the FreeType font.
+ * 3. Create a Cairo font referencing the FreeType font.
+ *
+ * The simultaneous interaction of Cairo and HarfBuzz with FreeType is
+ * a little finicky, so the order of the last two steps is important.
+ * We use HarfBuzz to set font variation settings (such as weight), if
+ * any. This modifies the underlying FreeType font, so we must create
+ * the Cairo font *after* this point for the changes to take effect.
+ *
+ * This doesn't seem like it should be necessary, as both HarfBuzz and
+ * Cairo reference the same FreeType font, but it is.
+ */
+
/* Setup FreeType. */
log_debug("Creating FreeType library.\n");
int err;
@@ -167,6 +184,7 @@ void entry_backend_harfbuzz_init(
log_error("Error loading font: %s\n", get_ft_error_string(err));
exit(EXIT_FAILURE);
}
+
err = FT_Set_Char_Size(
hb->ft_face,
font_size * 64,
@@ -178,6 +196,49 @@ void entry_backend_harfbuzz_init(
get_ft_error_string(err));
}
+ log_debug("Creating Harfbuzz font.\n");
+ hb->hb_font = hb_ft_font_create_referenced(hb->ft_face);
+
+ if (entry->font_variations[0] != 0) {
+ log_debug("Parsing font variations.\n");
+ }
+ char *saveptr = NULL;
+ char *variation = strtok_r(entry->font_variations, ",", &saveptr);
+ while (variation != NULL && hb->num_variations < N_ELEM(hb->hb_variations)) {
+ if (hb_variation_from_string(variation, -1, &hb->hb_variations[hb->num_variations])) {
+ hb->num_variations++;
+ } else {
+ log_error("Failed to parse font variation \"%s\".\n", variation);
+ }
+ variation = strtok_r(NULL, ",", &saveptr);
+ }
+
+ /*
+ * We need to set variations now and update the underlying FreeType
+ * font, as Cairo will then use the FreeType font for drawing.
+ */
+ hb_font_set_variations(hb->hb_font, hb->hb_variations, hb->num_variations);
+#ifndef NO_HARFBUZZ_FONT_CHANGED
+ hb_ft_hb_font_changed(hb->hb_font);
+#endif
+
+ if (entry->font_features[0] != 0) {
+ log_debug("Parsing font features.\n");
+ }
+ saveptr = NULL;
+ char *feature = strtok_r(entry->font_features, ",", &saveptr);
+ while (feature != NULL && hb->num_features < N_ELEM(hb->hb_features)) {
+ if (hb_feature_from_string(feature, -1, &hb->hb_features[hb->num_features])) {
+ hb->num_features++;
+ } else {
+ log_error("Failed to parse font feature \"%s\".\n", feature);
+ }
+ feature = strtok_r(NULL, ",", &saveptr);
+ }
+
+ log_debug("Creating Harfbuzz buffer.\n");
+ hb->hb_buffer = hb_buffer_create();
+
log_debug("Creating Cairo font.\n");
hb->cairo_face = cairo_ft_font_face_create_for_ft_face(hb->ft_face, 0);
@@ -193,34 +254,12 @@ void entry_backend_harfbuzz_init(
}
cairo_set_font_options(cr, opts);
-
/* We also need to set up the font for our other Cairo context. */
cairo_set_font_face(entry->cairo[1].cr, hb->cairo_face);
cairo_set_font_size(entry->cairo[1].cr, font_size);
cairo_set_font_options(entry->cairo[1].cr, opts);
cairo_font_options_destroy(opts);
-
- log_debug("Creating Harfbuzz font.\n");
- hb->hb_font = hb_ft_font_create_referenced(hb->ft_face);
-
- log_debug("Creating Harfbuzz buffer.\n");
- hb_buffer_t *buffer = hb_buffer_create();
- hb->hb_buffer = buffer;
- setup_hb_buffer(buffer);
-
-
- log_debug("Parsing font features.\n");
- char *saveptr = NULL;
- char *feature = strtok_r(entry->font_features, ",", &saveptr);
- while (feature != NULL && hb->num_features < N_ELEM(hb->hb_features)) {
- if (hb_feature_from_string(feature, -1, &hb->hb_features[hb->num_features])) {
- hb->num_features++;
- } else {
- log_error("Failed to parse font feature \"%s\".\n", feature);
- }
- feature = strtok_r(NULL, ",", &saveptr);
- }
}
void entry_backend_harfbuzz_destroy(struct entry *entry)
diff --git a/src/entry_backend/harfbuzz.h b/src/entry_backend/harfbuzz.h
index 4c45195..17b5945 100644
--- a/src/entry_backend/harfbuzz.h
+++ b/src/entry_backend/harfbuzz.h
@@ -7,6 +7,7 @@
#include FT_FREETYPE_H
#include <harfbuzz/hb.h>
+#define MAX_FONT_VARIATIONS 16
#define MAX_FONT_FEATURES 16
struct entry;
@@ -19,7 +20,9 @@ struct entry_backend_harfbuzz {
hb_font_t *hb_font;
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;
bool disable_hinting;
diff --git a/src/entry_backend/pango.c b/src/entry_backend/pango.c
index be3ccdb..7a63d1a 100644
--- a/src/entry_backend/pango.c
+++ b/src/entry_backend/pango.c
@@ -27,6 +27,11 @@ void entry_backend_pango_init(struct entry *entry, uint32_t *width, uint32_t *he
pango_font_description_set_size(
font_description,
entry->font_size * PANGO_SCALE);
+ if (entry->font_variations[0] != 0) {
+ pango_font_description_set_variations(
+ font_description,
+ entry->font_variations);
+ }
pango_context_set_font_description(context, font_description);
pango_font_description_free(font_description);
diff --git a/src/main.c b/src/main.c
index 994d58b..0c79ef2 100644
--- a/src/main.c
+++ b/src/main.c
@@ -754,6 +754,10 @@ static const struct wl_surface_listener dummy_surface_listener = {
static void usage()
{
+ /*
+ * This string literal is more than 4095 characters, which is the
+ * maximum size guaranteed to work in C, so we have to split it.
+ */
fprintf(stderr, "%s",
"Usage: tofi [options]\n"
"\n"
@@ -763,6 +767,7 @@ static void usage()
" --font <name|path> Font to use.\n"
" --font-size <pt> Point size of text.\n"
" --font-features <features> Set OpenType font features.\n"
+" --font-variations <variations> Set OpenType font variations.\n"
" --background-color <color> Color of the background.\n"
" --outline-width <px> Width of the border outlines.\n"
" --outline-color <color> Color of the border outlines.\n"
@@ -783,6 +788,8 @@ static void usage()
" --result-spacing <px> Spacing between results.\n"
" --min-input-width <px> Minimum input width in horizontal mode.\n"
" --width <px|%> Width of the window.\n"
+ );
+ fprintf(stderr, "%s",
" --height <px|%> Height of the window.\n"
" --corner-radius <px> Radius of window corners.\n"
" --output <name> Name of output to display window on.\n"
@@ -831,6 +838,7 @@ const struct option long_options[] = {
{"font", required_argument, NULL, 0},
{"font-size", required_argument, NULL, 0},
{"font-features", required_argument, NULL, 0},
+ {"font-variations", required_argument, NULL, 0},
{"num-results", required_argument, NULL, 0},
{"selection-color", required_argument, NULL, 0},
{"selection-match-color", required_argument, NULL, 0},