[PATCH 5/6] expo: video: Correct kerning output in console_truetype_putc_xy()

Simon Glass sjg at chromium.org
Sat May 24 17:41:11 CEST 2025


While the text is measured correctly, taking account of kerning
information, this is not used when actually displaying the text. This
results in a mismatch between the measurement and the output.

Fix this by adding the kerning offset to each character position.

Signed-off-by: Simon Glass <sjg at chromium.org>
---

 drivers/video/console_truetype.c | 12 +++++++-----
 test/boot/cedit.c                | 32 ++++++++++++++++----------------
 test/boot/expo.c                 | 20 ++++++++++----------
 test/dm/video.c                  | 16 ++++++++--------
 4 files changed, 41 insertions(+), 39 deletions(-)

diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c
index 6d2c2c2e177..a0458d2a6f5 100644
--- a/drivers/video/console_truetype.c
+++ b/drivers/video/console_truetype.c
@@ -287,19 +287,21 @@ static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y,
 	u8 *bits, *data;
 	int advance;
 	void *start, *end, *line;
-	int row;
+	int row, kern;
 
 	/* First get some basic metrics about this character */
 	stbtt_GetCodepointHMetrics(font, cp, &advance, &lsb);
 
 	/*
 	 * First out our current X position in fractional pixels. If we wrote
-	 * a character previously, using kerning to fine-tune the position of
+	 * a character previously, use kerning to fine-tune the position of
 	 * this character */
 	xpos = frac(VID_TO_PIXEL((double)x));
+	kern = 0;
 	if (vc_priv->last_ch) {
-		xpos += met->scale * stbtt_GetCodepointKernAdvance(font,
-							vc_priv->last_ch, cp);
+		kern = stbtt_GetCodepointKernAdvance(font, vc_priv->last_ch,
+						     cp);
+		xpos += met->scale * kern;
 	}
 
 	/*
@@ -310,7 +312,7 @@ static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y,
 	 */
 	x_shift = xpos - (double)tt_floor(xpos);
 	xpos += advance * met->scale;
-	width_frac = (int)VID_TO_POS(advance * met->scale);
+	width_frac = (int)VID_TO_POS((kern + advance) * met->scale);
 	if (x + width_frac >= vc_priv->xsize_frac)
 		return -EAGAIN;
 
diff --git a/test/boot/cedit.c b/test/boot/cedit.c
index 9d49fbdc306..3426bf13ec3 100644
--- a/test/boot/cedit.c
+++ b/test/boot/cedit.c
@@ -271,7 +271,7 @@ static int cedit_render(struct unit_test_state *uts)
 	ut_asserteq(ID_AC_OFF, menu->cur_item_id);
 
 	ut_assertok(expo_render(exp));
-	ut_asserteq(4888, video_compress_fb(uts, dev, false));
+	ut_asserteq(4926, video_compress_fb(uts, dev, false));
 	ut_assertok(video_check_copy_fb(uts, dev));
 
 	/* move to the second menu */
@@ -279,54 +279,54 @@ static int cedit_render(struct unit_test_state *uts)
 	act.select.id = ID_POWER_LOSS;
 	ut_assertok(cedit_do_action(exp, scn, vid_priv, &act));
 	ut_assertok(expo_render(exp));
-	ut_asserteq(4967, video_compress_fb(uts, dev, false));
+	ut_asserteq(5000, video_compress_fb(uts, dev, false));
 
 	/* open the menu */
 	act.type = EXPOACT_OPEN;
 	act.select.id = ID_POWER_LOSS;
 	ut_assertok(cedit_do_action(exp, scn, vid_priv, &act));
 	ut_assertok(expo_render(exp));
-	ut_asserteq(5397, video_compress_fb(uts, dev, false));
+	ut_asserteq(5390, video_compress_fb(uts, dev, false));
 
 	/* close the menu */
 	act.type = EXPOACT_CLOSE;
 	act.select.id = ID_POWER_LOSS;
 	ut_assertok(cedit_do_action(exp, scn, vid_priv, &act));
 	ut_assertok(expo_render(exp));
-	ut_asserteq(4967, video_compress_fb(uts, dev, false));
+	ut_asserteq(5000, video_compress_fb(uts, dev, false));
 
 	/* open the menu again to check it looks the same */
 	act.type = EXPOACT_OPEN;
 	act.select.id = ID_POWER_LOSS;
 	ut_assertok(cedit_do_action(exp, scn, vid_priv, &act));
 	ut_assertok(expo_render(exp));
-	ut_asserteq(5397, video_compress_fb(uts, dev, false));
+	ut_asserteq(5390, video_compress_fb(uts, dev, false));
 
 	/* close the menu */
 	act.type = EXPOACT_CLOSE;
 	act.select.id = ID_POWER_LOSS;
 	ut_assertok(cedit_do_action(exp, scn, vid_priv, &act));
 	ut_assertok(expo_render(exp));
-	ut_asserteq(4967, video_compress_fb(uts, dev, false));
+	ut_asserteq(5000, video_compress_fb(uts, dev, false));
 
 	act.type = EXPOACT_OPEN;
 	act.select.id = ID_POWER_LOSS;
 	ut_assertok(cedit_do_action(exp, scn, vid_priv, &act));
 	ut_assertok(expo_render(exp));
-	ut_asserteq(5397, video_compress_fb(uts, dev, false));
+	ut_asserteq(5390, video_compress_fb(uts, dev, false));
 
 	act.type = EXPOACT_POINT_ITEM;
 	act.select.id = ID_AC_ON;
 	ut_assertok(cedit_do_action(exp, scn, vid_priv, &act));
 	ut_assertok(expo_render(exp));
-	ut_asserteq(5341, video_compress_fb(uts, dev, false));
+	ut_asserteq(5363, video_compress_fb(uts, dev, false));
 
 	/* select it */
 	act.type = EXPOACT_SELECT;
 	act.select.id = ID_AC_ON;
 	ut_assertok(cedit_do_action(exp, scn, vid_priv, &act));
 	ut_assertok(expo_render(exp));
-	ut_asserteq(4939, video_compress_fb(uts, dev, false));
+	ut_asserteq(4964, video_compress_fb(uts, dev, false));
 
 	ut_asserteq(ID_AC_ON, menu->cur_item_id);
 
@@ -335,14 +335,14 @@ static int cedit_render(struct unit_test_state *uts)
 	act.select.id = ID_MACHINE_NAME;
 	ut_assertok(cedit_do_action(exp, scn, vid_priv, &act));
 	ut_assertok(expo_render(exp));
-	ut_asserteq(4850, video_compress_fb(uts, dev, false));
+	ut_asserteq(4868, video_compress_fb(uts, dev, false));
 
 	/* open it */
 	act.type = EXPOACT_OPEN;
 	act.select.id = ID_MACHINE_NAME;
 	ut_assertok(cedit_do_action(exp, scn, vid_priv, &act));
 	ut_assertok(expo_render(exp));
-	ut_asserteq(4883, video_compress_fb(uts, dev, false));
+	ut_asserteq(4871, video_compress_fb(uts, dev, false));
 
 	/*
 	 * Send some keypresses. Note that the console must be enabled so that
@@ -358,7 +358,7 @@ static int cedit_render(struct unit_test_state *uts)
 	ut_silence_console(uts);
 	ut_assertok(cedit_arange(exp, vid_priv, scn->id));
 	ut_assertok(expo_render(exp));
-	ut_asserteq(5033, video_compress_fb(uts, dev, false));
+	ut_asserteq(5076, video_compress_fb(uts, dev, false));
 
 	expo_destroy(exp);
 	cur_exp = NULL;
@@ -401,7 +401,7 @@ static int cedit_render_lineedit(struct unit_test_state *uts)
 	ut_asserteq(20, tline->pos);
 
 	ut_assertok(expo_render(exp));
-	ut_asserteq(5315, video_compress_fb(uts, dev, false));
+	ut_asserteq(5344, video_compress_fb(uts, dev, false));
 	ut_assertok(video_check_copy_fb(uts, dev));
 
 	/* move to the line-edit field */
@@ -409,14 +409,14 @@ static int cedit_render_lineedit(struct unit_test_state *uts)
 	act.select.id = ID_MACHINE_NAME;
 	ut_assertok(cedit_do_action(exp, scn, vid_priv, &act));
 	ut_assertok(expo_render(exp));
-	ut_asserteq(5372, video_compress_fb(uts, dev, false));
+	ut_asserteq(5408, video_compress_fb(uts, dev, false));
 
 	/* open it */
 	act.type = EXPOACT_OPEN;
 	act.select.id = ID_MACHINE_NAME;
 	ut_assertok(cedit_do_action(exp, scn, vid_priv, &act));
 	ut_assertok(expo_render(exp));
-	ut_asserteq(5259, video_compress_fb(uts, dev, false));
+	ut_asserteq(5291, video_compress_fb(uts, dev, false));
 
 	/* delete some characters */
 	ut_unsilence_console(uts);
@@ -427,7 +427,7 @@ static int cedit_render_lineedit(struct unit_test_state *uts)
 
 	ut_assertok(cedit_arange(exp, vid_priv, scn->id));
 	ut_assertok(expo_render(exp));
-	ut_asserteq(5126, video_compress_fb(uts, dev, false));
+	ut_asserteq(5209, video_compress_fb(uts, dev, false));
 
 	expo_destroy(exp);
 	cur_exp = NULL;
diff --git a/test/boot/expo.c b/test/boot/expo.c
index 239591ff6cd..17d5c1a9db2 100644
--- a/test/boot/expo.c
+++ b/test/boot/expo.c
@@ -684,17 +684,17 @@ static int expo_render_image(struct unit_test_state *uts)
 	/* render it */
 	expo_set_scene_id(exp, SCENE1);
 	ut_assertok(expo_render(exp));
-	ut_asserteq(18786, video_compress_fb(uts, dev, false));
+	ut_asserteq(18792, video_compress_fb(uts, dev, false));
 
 	ut_asserteq(0, scn->highlight_id);
 	ut_assertok(scene_arrange(scn));
 	ut_asserteq(0, scn->highlight_id);
 	ut_assertok(expo_render(exp));
-	ut_asserteq(20433, video_compress_fb(uts, dev, false));
+	ut_asserteq(20401, video_compress_fb(uts, dev, false));
 
 	ut_assertok(scene_arrange(scn));
 	ut_assertok(expo_render(exp));
-	ut_asserteq(20433, video_compress_fb(uts, dev, false));
+	ut_asserteq(20401, video_compress_fb(uts, dev, false));
 
 	scene_set_highlight_id(scn, OBJ_MENU);
 	ut_asserteq(OBJ_MENU, scn->highlight_id);
@@ -706,7 +706,7 @@ static int expo_render_image(struct unit_test_state *uts)
 	ut_assert(!(obj->flags & SCENEOF_HIDE));
 
 	ut_assertok(expo_render(exp));
-	ut_asserteq(20433, video_compress_fb(uts, dev, false));
+	ut_asserteq(20401, video_compress_fb(uts, dev, false));
 
 	/* move down */
 	ut_assertok(expo_send_key(exp, BKEY_DOWN));
@@ -719,7 +719,7 @@ static int expo_render_image(struct unit_test_state *uts)
 	ut_asserteq(ITEM2, scene_menu_get_cur_item(scn, OBJ_MENU));
 	ut_assertok(scene_arrange(scn));
 	ut_assertok(expo_render(exp));
-	ut_asserteq(19673, video_compress_fb(uts, dev, false));
+	ut_asserteq(19650, video_compress_fb(uts, dev, false));
 	ut_assertok(video_check_copy_fb(uts, dev));
 
 	/* hide the text editor since the following tets don't need it */
@@ -728,18 +728,18 @@ static int expo_render_image(struct unit_test_state *uts)
 	/* do some alignment checks */
 	ut_assertok(scene_obj_set_halign(scn, OBJ_TEXT3, SCENEOA_CENTRE));
 	ut_assertok(expo_render(exp));
-	ut_asserteq(16368, video_compress_fb(uts, dev, false));
+	ut_asserteq(16322, video_compress_fb(uts, dev, false));
 	ut_assertok(scene_obj_set_halign(scn, OBJ_TEXT3, SCENEOA_RIGHT));
 	ut_assertok(expo_render(exp));
-	ut_asserteq(16321, video_compress_fb(uts, dev, false));
+	ut_asserteq(16276, video_compress_fb(uts, dev, false));
 
 	ut_assertok(scene_obj_set_halign(scn, OBJ_TEXT3, SCENEOA_LEFT));
 	ut_assertok(scene_obj_set_valign(scn, OBJ_TEXT3, SCENEOA_CENTRE));
 	ut_assertok(expo_render(exp));
-	ut_asserteq(18763, video_compress_fb(uts, dev, false));
+	ut_asserteq(18753, video_compress_fb(uts, dev, false));
 	ut_assertok(scene_obj_set_valign(scn, OBJ_TEXT3, SCENEOA_BOTTOM));
 	ut_assertok(expo_render(exp));
-	ut_asserteq(18714, video_compress_fb(uts, dev, false));
+	ut_asserteq(18696, video_compress_fb(uts, dev, false));
 
 	/* make sure only the preview for the second item is shown */
 	obj = scene_obj_find(scn, ITEM1_PREVIEW, SCENEOBJT_NONE);
@@ -765,7 +765,7 @@ static int expo_render_image(struct unit_test_state *uts)
 	exp->show_highlight = true;
 	ut_assertok(scene_arrange(scn));
 	ut_assertok(expo_render(exp));
-	ut_asserteq(18844, video_compress_fb(uts, dev, false));
+	ut_asserteq(18805, video_compress_fb(uts, dev, false));
 
 	/* now try in text mode */
 	expo_set_text_mode(exp, true);
diff --git a/test/dm/video.c b/test/dm/video.c
index ecf74605b5c..e48f6b078c7 100644
--- a/test/dm/video.c
+++ b/test/dm/video.c
@@ -582,7 +582,7 @@ static int dm_test_video_truetype(struct unit_test_state *uts)
 	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
 	vidconsole_put_string(con, test_string);
 	vidconsole_put_stringn(con, test_string, 30);
-	ut_asserteq(13184, video_compress_fb(uts, dev, false));
+	ut_asserteq(13055, video_compress_fb(uts, dev, false));
 	ut_assertok(video_check_copy_fb(uts, dev));
 
 	return 0;
@@ -604,7 +604,7 @@ static int dm_test_video_truetype_scroll(struct unit_test_state *uts)
 	ut_assertok(video_get_nologo(uts, &dev));
 	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
 	vidconsole_put_string(con, test_string);
-	ut_asserteq(34287, video_compress_fb(uts, dev, false));
+	ut_asserteq(34248, video_compress_fb(uts, dev, false));
 	ut_assertok(video_check_copy_fb(uts, dev));
 
 	return 0;
@@ -626,7 +626,7 @@ static int dm_test_video_truetype_bs(struct unit_test_state *uts)
 	ut_assertok(video_get_nologo(uts, &dev));
 	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
 	vidconsole_put_string(con, test_string);
-	ut_asserteq(29471, video_compress_fb(uts, dev, false));
+	ut_asserteq(29223, video_compress_fb(uts, dev, false));
 	ut_assertok(video_check_copy_fb(uts, dev));
 
 	return 0;
@@ -665,7 +665,7 @@ static int dm_test_video_copy(struct unit_test_state *uts)
 	vidconsole_put_string(con, test_string);
 	vidconsole_put_string(con, test_string);
 
-	ut_asserteq(6678, video_compress_fb(uts, dev, false));
+	ut_asserteq(6884, video_compress_fb(uts, dev, false));
 	ut_assertok(video_check_copy_fb(uts, dev));
 
 	/*
@@ -690,8 +690,8 @@ static int dm_test_video_copy(struct unit_test_state *uts)
 	vidconsole_put_string(con, test_string);
 	vidconsole_put_string(con, test_string);
 	video_sync(dev, true);
-	ut_asserteq(7589, video_compress_fb(uts, dev, false));
-	ut_asserteq(7704, video_compress_fb(uts, dev, true));
+	ut_asserteq(7621, video_compress_fb(uts, dev, false));
+	ut_asserteq(7741, video_compress_fb(uts, dev, true));
 
 	return 0;
 }
@@ -746,7 +746,7 @@ static int dm_test_video_damage(struct unit_test_state *uts)
 	ut_asserteq(0, priv->damage.xend);
 	ut_asserteq(0, priv->damage.yend);
 
-	ut_asserteq(7339, video_compress_fb(uts, dev, false));
+	ut_asserteq(7335, video_compress_fb(uts, dev, false));
 	ut_assertok(video_check_copy_fb(uts, dev));
 
 	return 0;
@@ -896,7 +896,7 @@ static int dm_test_video_silence(struct unit_test_state *uts)
 	printf("final message: console\n");
 	vidconsole_put_string(con, "final message: video\n");
 
-	ut_asserteq(3892, video_compress_fb(uts, dev, false));
+	ut_asserteq(3944, video_compress_fb(uts, dev, false));
 	ut_assertok(video_check_copy_fb(uts, dev));
 
 	return 0;
-- 
2.43.0

base-commit: e3ced530e543c9f24cbc66430abc6109ce8df015
branch: expa


More information about the U-Boot mailing list