[Concept,13/42] video: truetype: Handle rendering of bitmap fonts

Message ID 20250919201507.4024144-14-sjg@u-boot.org
State New
Headers
Series video: Support a cursor more generally |

Commit Message

Simon Glass Sept. 19, 2025, 8:14 p.m. UTC
  From: Simon Glass <sjg@chromium.org>

Complete the support for this feature by dealing with rendering, the
moving to a particular row/column and scrolling.

Provide a simple test to check that things look right.

Allow omitting the font name to request the default font.

Fix an errant tab nearby.

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <sjg@chromium.org>
---

 cmd/font.c                        |  3 ---
 doc/usage/cmd/font.rst            | 16 ++++++++++--
 drivers/video/console_truetype.c  | 37 +++++++++++++++++++-------
 drivers/video/vidconsole-uclass.c |  1 +
 test/cmd/font.c                   |  7 +++--
 test/dm/video.c                   | 43 ++++++++++++++++++++++++++++++-
 6 files changed, 89 insertions(+), 18 deletions(-)
  

Patch

diff --git a/cmd/font.c b/cmd/font.c
index 36e41203654..384751e787a 100644
--- a/cmd/font.c
+++ b/cmd/font.c
@@ -31,9 +31,6 @@  static int do_font_select(struct cmd_tbl *cmdtp, int flag, int argc,
 	uint size = 0;
 	int ret;
 
-	if (argc < 2)
-		return CMD_RET_USAGE;
-
 	if (uclass_first_device_err(UCLASS_VIDEO_CONSOLE, &dev))
 		return CMD_RET_FAILURE;
 	name = argv[1];
diff --git a/doc/usage/cmd/font.rst b/doc/usage/cmd/font.rst
index 44a04f5d075..6e313e70c7a 100644
--- a/doc/usage/cmd/font.rst
+++ b/doc/usage/cmd/font.rst
@@ -12,7 +12,7 @@  Synopsis
 ::
 
     font list
-    font select <name> [<size>]
+    font select [<name> [<size>]]
     font size [<size>]
 
 Description
@@ -25,11 +25,13 @@  font list
 ~~~~~~~~~
 
 This lists the available fonts, using the name of the font file in the build.
+Any enabled bitmap fonts are listed as well.
 
 font select
 ~~~~~~~~~~~
 
-This selects a new font and optionally changes the size.
+This selects a new font and optionally changes the size. If the name is not
+provided, the default font is used.
 
 font size
 ~~~~~~~~~
@@ -50,6 +52,16 @@  Examples
     => font select cantoraone_regular 20
     =>
 
+This shows an example of selecting a bitmap font Truetype is active::
+
+    => font list
+    8x16
+    12x22
+    nimbus_sans_l_regular
+    cantoraone_regular
+    => font sel 8x16
+
+
 Configuration
 -------------
 
diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c
index eb9e7f55d68..43274bb8f66 100644
--- a/drivers/video/console_truetype.c
+++ b/drivers/video/console_truetype.c
@@ -13,6 +13,7 @@ 
 #include <video.h>
 #include <video_console.h>
 #include <video_font.h>
+#include "vidconsole_internal.h"
 
 /* Functions needed by stb_truetype.h */
 static int tt_floor(double val)
@@ -197,11 +198,17 @@  static int console_truetype_set_row(struct udevice *dev, uint row, int clr)
 	struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
 	struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
 	struct console_tt_priv *priv = dev_get_priv(dev);
-	struct console_tt_metrics *met = priv->cur_met;
 	void *end, *line;
+	int font_height;
+
+	/* Get font height from current font type */
+	if (priv->cur_fontdata)
+		font_height = priv->cur_fontdata->height;
+	else
+		font_height = priv->cur_met->font_size;
 
-	line = vid_priv->fb + row * met->font_size * vid_priv->line_length;
-	end = line + met->font_size * vid_priv->line_length;
+	line = vid_priv->fb + row * font_height * vid_priv->line_length;
+	end = line + font_height * vid_priv->line_length;
 
 	switch (vid_priv->bpix) {
 	case VIDEO_BPP8: {
@@ -250,17 +257,22 @@  static int console_truetype_move_rows(struct udevice *dev, uint rowdst,
 	struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
 	struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
 	struct console_tt_priv *priv = dev_get_priv(dev);
-	struct console_tt_metrics *met = priv->cur_met;
 	void *dst;
 	void *src;
-	int i, diff;
+	int i, diff, font_height;
 
-	dst = vid_priv->fb + rowdst * met->font_size * vid_priv->line_length;
-	src = vid_priv->fb + rowsrc * met->font_size * vid_priv->line_length;
-	memmove(dst, src, met->font_size * vid_priv->line_length * count);
+	/* Get font height from current font type */
+	if (priv->cur_fontdata)
+		font_height = priv->cur_fontdata->height;
+	else
+		font_height = priv->cur_met->font_size;
+
+	dst = vid_priv->fb + rowdst * font_height * vid_priv->line_length;
+	src = vid_priv->fb + rowsrc * font_height * vid_priv->line_length;
+	memmove(dst, src, font_height * vid_priv->line_length * count);
 
 	/* Scroll up our position history */
-	diff = (rowsrc - rowdst) * met->font_size;
+	diff = (rowsrc - rowdst) * font_height;
 	for (i = 0; i < priv->pos_ptr; i++)
 		priv->pos[i].ypos -= diff;
 
@@ -281,7 +293,7 @@  static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y,
 	struct video_priv *vid_priv = dev_get_uclass_priv(vid);
 	struct console_tt_priv *priv = dev_get_priv(dev);
 	struct console_tt_metrics *met = priv->cur_met;
-	stbtt_fontinfo *font = &met->font;
+	stbtt_fontinfo *font;
 	int width, height, xoff, yoff;
 	double xpos, x_shift;
 	int lsb;
@@ -292,7 +304,12 @@  static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y,
 	void *start, *end, *line;
 	int row, kern;
 
+	/* Use fixed font if selected */
+	if (priv->cur_fontdata)
+		return console_fixed_putc_xy(dev, x, y, cp, priv->cur_fontdata);
+
 	/* First get some basic metrics about this character */
+	font = &met->font;
 	stbtt_GetCodepointHMetrics(font, cp, &advance, &lsb);
 
 	/*
diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c
index b5f0b79bcf6..cb7212e9730 100644
--- a/drivers/video/vidconsole-uclass.c
+++ b/drivers/video/vidconsole-uclass.c
@@ -835,4 +835,5 @@  void vidconsole_set_bitmap_font(struct udevice *dev,
 		vc_priv->rows = vid_priv->ysize / fontdata->height;
 		/* xsize_frac is set in vidconsole_pre_probe() */
 	}
+	vc_priv->xstart_frac = 0;
 }
diff --git a/test/cmd/font.c b/test/cmd/font.c
index b2610ddef8d..ce694fef7e4 100644
--- a/test/cmd/font.c
+++ b/test/cmd/font.c
@@ -82,9 +82,12 @@  static int font_test_base(struct unit_test_state *uts)
 	ut_assert_nextline("30");
 	ut_assertok(ut_check_console_end(uts));
 
+	ut_assertok(run_command("font select", 0));
+	ut_assertok(ut_check_console_end(uts));
+
 	ut_assertok(vidconsole_get_font_size(dev, &name, &size));
-	ut_asserteq_str("cantoraone_regular", name);
-	ut_asserteq(30, size);
+	ut_asserteq_str("nimbus_sans_l_regular", name);
+	ut_asserteq(CONFIG_CONSOLE_TRUETYPE_SIZE, size);
 
 	return 0;
 }
diff --git a/test/dm/video.c b/test/dm/video.c
index a48d0c0411c..3ec12956909 100644
--- a/test/dm/video.c
+++ b/test/dm/video.c
@@ -944,7 +944,7 @@  static int dm_test_video_box(struct unit_test_state *uts)
 	video_draw_box(dev, 500, 100, 600, 200, 20,
 		       video_index_to_colour(priv, VID_LIGHT_RED), false);
 	ut_asserteq(133, video_compress_fb(uts, dev, false));
-	
+
 	/* test filled boxes */
 	video_draw_box(dev, 150, 250, 200, 300, 0,
 		       video_index_to_colour(priv, VID_GREEN), true);
@@ -956,3 +956,44 @@  static int dm_test_video_box(struct unit_test_state *uts)
 	return 0;
 }
 DM_TEST(dm_test_video_box, UTF_SCAN_FDT);
+
+/* font switching between TrueType and bitmap fonts */
+static int dm_test_video_font_switch(struct unit_test_state *uts)
+{
+	struct udevice *dev, *con;
+	const char *truetype_text =
+		"This is a long line of text written with TrueType font that "
+		"should wrap to multiple lines to test the multi-line "
+		"functionality properly. This is the second part of TrueType "
+		"text that should also be long enough to wrap and test the "
+		"line handling.";
+	const char *bitmap_text =
+		"Now this is bitmap font text that spans multiple lines and "
+		"should be rendered with the standard 8x16 bitmap font instead "
+		"of TrueType. More of the line of-bitmap text for testing "
+		"purposes.";
+	const char *final_truetype_text =
+		"Finally back to TrueType font for this concluding multi-line "
+		"text that demonstrates the font switching functionality "
+		"working correctly.\nFinal line of TrueType text to complete "
+		"the test.\n";
+
+	ut_assertok(video_get_nologo(uts, &dev));
+	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
+
+	/* Start with TrueType font and write multi-line text */
+	vidconsole_put_string(con, truetype_text);
+
+	/* Switch to bitmap font */
+	ut_assertok(vidconsole_select_font(con, "8x16", 0));
+	vidconsole_put_string(con, bitmap_text);
+
+	/* Switch back to TrueType font */
+	ut_assertok(vidconsole_select_font(con, NULL, 0));
+	vidconsole_put_string(con, final_truetype_text);
+
+	ut_asserteq(14892, video_compress_fb(uts, dev, false));
+
+	return 0;
+}
+DM_TEST(dm_test_video_font_switch, UTF_SCAN_PDATA | UTF_SCAN_FDT);