]> git.ipfire.org Git - thirdparty/plymouth.git/commitdiff
label-freetype: implement bold font handling
authorFerdinand Bachmann <ferdinand.bachmann@yrlf.at>
Tue, 29 Oct 2024 20:59:57 +0000 (21:59 +0100)
committerFerdinand Bachmann <ferdinand.bachmann@yrlf.at>
Wed, 30 Oct 2024 09:50:22 +0000 (10:50 +0100)
Bold monospace fonts are prominently used in the console output printed
by systemd. Without them, the output looks incorrect compared to pango.
This still is far from a complete implementation of rich text, but
brings label-freetype much closer to what label-pango does for the
default theme.

This commit introduces a glyph_face variable in load_glyphs() that holds
the correct face for the current glyph (label->face or
label->bold_face). This face is then passed on to load_glyph() and
finish_measuring_line() to ensure correct font measurements.

src/plugins/controls/label-freetype/plugin.c

index 8064519aa288752a61dbbb4b5e4fb5459bb32d50..2594c800ac771222364a8ebadd29016e15e98395 100644 (file)
@@ -42,7 +42,9 @@
 
 /* This is used if fontconfig (fc-match) is not available, like in the initrd. */
 #define FONT_FALLBACK "/usr/share/fonts/Plymouth.ttf"
+#define BOLD_FONT_FALLBACK "/usr/share/fonts/Plymouth-bold.ttf"
 #define MONOSPACE_FONT_FALLBACK "/usr/share/fonts/Plymouth-monospace.ttf"
+#define MONOSPACE_BOLD_FONT_FALLBACK "/usr/share/fonts/Plymouth-monospace-bold.ttf"
 
 /* This is a little sketchy... It relies on implementation details of the compiler
  * but it makes dealing with the fixed point math freetype uses much more pleasant,
@@ -85,6 +87,7 @@ struct _ply_label_plugin_control
 
         FT_Library            library;
         FT_Face               face;
+        FT_Face               bold_face;
         char                 *font;
 
         char                 *text;
@@ -141,6 +144,26 @@ find_default_font_path (void)
         return fc_match_out;
 }
 
+static const char *
+find_default_bold_font_path (void)
+{
+        FILE *fp;
+        static char fc_match_out[PATH_MAX];
+
+        fp = popen ("/usr/bin/fc-match -f %{file} :weight=bold", "r");
+        if (!fp)
+                return BOLD_FONT_FALLBACK;
+
+        fgets (fc_match_out, sizeof(fc_match_out), fp);
+
+        pclose (fp);
+
+        if (strcmp (fc_match_out, "") == 0)
+                return BOLD_FONT_FALLBACK;
+
+        return fc_match_out;
+}
+
 static const char *
 find_default_monospace_font_path (void)
 {
@@ -161,6 +184,26 @@ find_default_monospace_font_path (void)
         return fc_match_out;
 }
 
+static const char *
+find_default_monospace_bold_font_path (void)
+{
+        FILE *fp;
+        static char fc_match_out[PATH_MAX];
+
+        fp = popen ("/usr/bin/fc-match -f %{file} monospace:weight=bold", "r");
+        if (!fp)
+                return MONOSPACE_BOLD_FONT_FALLBACK;
+
+        fgets (fc_match_out, sizeof(fc_match_out), fp);
+
+        pclose (fp);
+
+        if (strcmp (fc_match_out, "") == 0)
+                return MONOSPACE_BOLD_FONT_FALLBACK;
+
+        return fc_match_out;
+}
+
 static ply_label_plugin_control_t *
 create_control (void)
 {
@@ -213,6 +256,7 @@ destroy_control (ply_label_plugin_control_t *label)
         free (label->text);
         free (label->font);
         FT_Done_Face (label->face);
+        FT_Done_Face (label->bold_face);
         FT_Done_FreeType (label->library);
 
         free (label);
@@ -235,14 +279,15 @@ get_height_of_control (ply_label_plugin_control_t *label)
 static FT_GlyphSlot
 load_glyph (ply_label_plugin_control_t *label,
             ply_load_glyph_action_t     action,
-            const char                 *input_text)
+            const char                 *input_text,
+            FT_Face                     face)
 {
         FT_Error error;
         size_t character_size;
         wchar_t character;
         FT_Int32 load_flags = FT_LOAD_TARGET_LIGHT;
 
-        if (label->face == NULL)
+        if (face == NULL)
                 return NULL;
 
         character_size = mbrtowc (&character, input_text, PLY_UTF8_CHARACTER_SIZE_MAX, NULL);
@@ -255,12 +300,12 @@ load_glyph (ply_label_plugin_control_t *label,
         if (action == PLY_LOAD_GLYPH_ACTION_RENDER)
                 load_flags |= FT_LOAD_RENDER;
 
-        error = FT_Load_Char (label->face, (FT_ULong) character, load_flags);
+        error = FT_Load_Char (face, (FT_ULong) character, load_flags);
 
         if (error)
                 return NULL;
 
-        return label->face->glyph;
+        return face->glyph;
 }
 
 static void
@@ -424,16 +469,17 @@ static void
 finish_measuring_line (ply_label_plugin_control_t *label,
                        ply_freetype_unit_t        *glyph_x,
                        ply_freetype_unit_t        *glyph_y,
-                       ply_rectangle_t            *dimensions)
+                       ply_rectangle_t            *dimensions,
+                       FT_Face                     face)
 {
 
         ply_freetype_unit_t line_height;
         ply_rectangle_t *entry;
 
-        if (label->face == NULL)
+        if (face == NULL)
                 return;
 
-        line_height.as_integer = label->face->size->metrics.ascender + -label->face->size->metrics.descender;
+        line_height.as_integer = face->size->metrics.ascender + -face->size->metrics.descender;
 
         dimensions->x = label->area.x * label->scale_factor;
 
@@ -485,6 +531,7 @@ load_glyphs (ply_label_plugin_control_t *label,
              ply_pixel_buffer_t         *pixel_buffer)
 {
         FT_GlyphSlot glyph = NULL;
+        FT_Face glyph_face = label->face;
         ply_rich_text_iterator_t rich_text_iterator;
         ply_utf8_string_iterator_t utf8_string_iterator;
         uint32_t *target = NULL;
@@ -570,6 +617,12 @@ load_glyphs (ply_label_plugin_control_t *label,
 
                         current_character = rich_text_character->bytes;
 
+                        if (label->bold_face != NULL && rich_text_character->style.bold_enabled) {
+                                glyph_face = label->bold_face;
+                        } else {
+                                glyph_face = label->face;
+                        }
+
                         if (action == PLY_LOAD_GLYPH_ACTION_RENDER) {
                                 look_up_rgb_color_from_terminal_color (label,
                                                                        rich_text_character->style.foreground_color,
@@ -587,26 +640,27 @@ load_glyphs (ply_label_plugin_control_t *label,
                                 break;
                 }
 
-                glyph = load_glyph (label, action, current_character);
+
+                glyph = load_glyph (label, action, current_character, glyph_face);
 
                 if (glyph == NULL)
                         continue;
 
                 if (is_first_character) {
                         /* Move pen to the first character's base line */
-                        glyph_y.as_integer += label->face->size->metrics.ascender;
+                        glyph_y.as_integer += glyph_face->size->metrics.ascender;
                 }
 
                 if (*current_character == '\n') {
                         if (action == PLY_LOAD_GLYPH_ACTION_MEASURE)
-                                finish_measuring_line (label, &glyph_x, &glyph_y, line_dimensions);
+                                finish_measuring_line (label, &glyph_x, &glyph_y, line_dimensions, glyph_face);
                         else
                                 line_dimensions = dimensions_of_lines[line_number++];
 
                         glyph_x.as_pixels_unit.pixels = line_dimensions->x;
                         glyph_y.as_pixels_unit.pixels = line_dimensions->y;
 
-                        glyph_y.as_integer += label->face->size->metrics.ascender;
+                        glyph_y.as_integer += glyph_face->size->metrics.ascender;
                         continue;
                 }
 
@@ -635,7 +689,7 @@ load_glyphs (ply_label_plugin_control_t *label,
                 if (!is_first_character) {
                         FT_Vector kerning_space;
 
-                        error = FT_Get_Kerning (label->face, previous_glyph_index, glyph->glyph_index, FT_KERNING_DEFAULT, &kerning_space);
+                        error = FT_Get_Kerning (glyph_face, previous_glyph_index, glyph->glyph_index, FT_KERNING_DEFAULT, &kerning_space);
 
                         if (error == 0)
                                 glyph_x.as_integer += kerning_space.x;
@@ -650,7 +704,7 @@ load_glyphs (ply_label_plugin_control_t *label,
                 if (!is_first_character) {
                         char *text = NULL;
 
-                        finish_measuring_line (label, &glyph_x, &glyph_y, line_dimensions);
+                        finish_measuring_line (label, &glyph_x, &glyph_y, line_dimensions, glyph_face);
 
                         if (ply_is_tracing ()) {
                                 if (label->rich_text != NULL)
@@ -783,29 +837,51 @@ set_font_for_control (ply_label_plugin_control_t *label,
         if (strstr (font, "Mono") || strstr (font, "mono")) {
                 if (!label->is_monospaced) {
                         FT_Done_Face (label->face);
+                        FT_Done_Face (label->bold_face);
+                        label->face = NULL;
+                        label->bold_face = NULL;
 
                         font_path = find_default_monospace_font_path ();
 
                         if (font_path != NULL)
                                 error = FT_New_Face (label->library, font_path, 0, &label->face);
 
+                        font_path = find_default_monospace_bold_font_path ();
+
+                        /* Ignore errors when loading bold face to allow
+                         * fallback to regular face */
+                        if (font_path != NULL)
+                                FT_New_Face (label->library, font_path, 0, &label->bold_face);
+
                         label->is_monospaced = true;
                 }
         } else {
                 if (label->is_monospaced || label->face == NULL) {
                         FT_Done_Face (label->face);
+                        FT_Done_Face (label->bold_face);
+                        label->face = NULL;
+                        label->bold_face = NULL;
 
                         font_path = find_default_font_path ();
 
                         if (font_path != NULL)
                                 error = FT_New_Face (label->library, font_path, 0, &label->face);
 
+                        font_path = find_default_bold_font_path ();
+
+                        /* Ignore errors when loading bold face to allow
+                         * fallback to regular face */
+                        if (font_path != NULL)
+                                FT_New_Face (label->library, font_path, 0, &label->bold_face);
+
                         label->is_monospaced = false;
                 }
         }
         if (error != 0) {
                 FT_Done_Face (label->face);
+                FT_Done_Face (label->bold_face);
                 label->face = NULL;
+                label->bold_face = NULL;
 
                 ply_trace ("Could not load font, error %d", error);
                 return;
@@ -834,6 +910,13 @@ set_font_for_control (ply_label_plugin_control_t *label,
         else
                 FT_Set_Char_Size (label->face, size.as_integer, 0, dpi * label->scale_factor, 0);
 
+        if (label->bold_face != NULL) {
+                if (size_in_pixels)
+                        FT_Set_Pixel_Sizes (label->bold_face, 0, size.as_pixels_unit.pixels * label->scale_factor);
+                else
+                        FT_Set_Char_Size (label->bold_face, size.as_integer, 0, dpi * label->scale_factor, 0);
+        }
+
         /* Ignore errors, to keep the current size. */
         trigger_redraw (label, true);
 }