diff mbox series

[v2,1/1] video: fix positioning in TrueType console

Message ID 20211028051907.86539-1-xypron.glpk@gmx.de
State Superseded
Delegated to: Anatolij Gustschin
Headers show
Series [v2,1/1] video: fix positioning in TrueType console | expand

Commit Message

Heinrich Schuchardt Oct. 28, 2021, 5:19 a.m. UTC
With the patch accurate positioning is possible for mono-typed fonts:

Fix the return value of console_truetype_putc_xy(). The current position
is passed as parameter x. Some part of x represents a fractional pixel.
The return value represents how much the character position must be
advanced. This should only comprise the width of the current character and
not the preexisting fractional pixel position.

Characters are not square. As all characters of a mono-type font we can
take the width of any character. 'W' as one of the widest ANSI characters
provides also a good value for variable width fonts.

The character width must be a float.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
---
v2:
	Adjust hash values in tests
---
 drivers/video/console_truetype.c | 27 ++++++++++++++++++++-------
 include/video_console.h          |  2 +-
 test/dm/video.c                  |  6 +++---
 3 files changed, 24 insertions(+), 11 deletions(-)

--
2.30.2

Comments

Heinrich Schuchardt Oct. 28, 2021, 7:07 a.m. UTC | #1
On 10/28/21 7:19 AM, Heinrich Schuchardt wrote:
> With the patch accurate positioning is possible for mono-typed fonts:
>
> Fix the return value of console_truetype_putc_xy(). The current position
> is passed as parameter x. Some part of x represents a fractional pixel.
> The return value represents how much the character position must be
> advanced. This should only comprise the width of the current character and
> not the preexisting fractional pixel position.
>
> Characters are not square. As all characters of a mono-type font we can
> take the width of any character. 'W' as one of the widest ANSI characters
> provides also a good value for variable width fonts.
>
> The character width must be a float.
>
> Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
> ---
> v2:
> 	Adjust hash values in tests

There is still something wrong for systems without float support:

undefined reference to `__aeabi_dmul'

We should keep usage of floats restricted to truetype.

Best regards

Heinrich

> ---
>   drivers/video/console_truetype.c | 27 ++++++++++++++++++++-------
>   include/video_console.h          |  2 +-
>   test/dm/video.c                  |  6 +++---
>   3 files changed, 24 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c
> index d9ad52cce0..6fe238eab3 100644
> --- a/drivers/video/console_truetype.c
> +++ b/drivers/video/console_truetype.c
> @@ -209,7 +209,7 @@ static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y,
>   	int width_frac, linenum;
>   	struct pos_info *pos;
>   	u8 *bits, *data;
> -	int advance;
> +	int advance, kern_adv;
>   	void *start, *line, *sync_start, *sync_end;
>   	int row, ret;
>   	int bg_r, bg_g, bg_b;
> @@ -224,8 +224,11 @@ static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y,
>   	 * this character */
>   	xpos = frac(VID_TO_PIXEL((double)x));
>   	if (vc_priv->last_ch) {
> -		xpos += priv->scale * stbtt_GetCodepointKernAdvance(font,
> -							vc_priv->last_ch, ch);
> +		kern_adv = stbtt_GetCodepointKernAdvance(font, vc_priv->last_ch,
> +							 ch);
> +		xpos += priv->scale * kern_adv;
> +	} else {
> +		kern_adv = 0;
>   	}
>
>   	/*
> @@ -236,8 +239,8 @@ static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y,
>   	 */
>   	x_shift = xpos - (double)tt_floor(xpos);
>   	xpos += advance * priv->scale;
> -	width_frac = (int)VID_TO_POS(xpos);
> -	if (x + width_frac >= vc_priv->xsize_frac)
> +	width_frac = VID_TO_POS(priv->scale * (kern_adv + advance));
> +	if (x + (int)VID_TO_POS(xpos) >= vc_priv->xsize_frac)
>   		return -EAGAIN;
>
>   	/* Write the current cursor position into history */
> @@ -585,20 +588,21 @@ static int console_truetype_probe(struct udevice *dev)
>   	struct udevice *vid_dev = dev->parent;
>   	struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev);
>   	stbtt_fontinfo *font = &priv->font;
> -	int ascent;
> +	int advance, ascent, lsb;
>
>   	debug("%s: start\n", __func__);
> +
>   	if (vid_priv->font_size)
>   		priv->font_size = vid_priv->font_size;
>   	else
>   		priv->font_size = CONFIG_CONSOLE_TRUETYPE_SIZE;
> +
>   	priv->font_data = console_truetype_find_font();
>   	if (!priv->font_data) {
>   		debug("%s: Could not find any fonts\n", __func__);
>   		return -EBFONT;
>   	}
>
> -	vc_priv->x_charsize = priv->font_size;
>   	vc_priv->y_charsize = priv->font_size;
>   	vc_priv->xstart_frac = VID_TO_POS(2);
>   	vc_priv->cols = vid_priv->xsize / priv->font_size;
> @@ -612,6 +616,15 @@ static int console_truetype_probe(struct udevice *dev)
>
>   	/* Pre-calculate some things we will need regularly */
>   	priv->scale = stbtt_ScaleForPixelHeight(font, priv->font_size);
> +
> +	/* Assuming that 'W' is the widest character */
> +	stbtt_GetCodepointHMetrics(font, 'W', &advance, &lsb);
> +	advance += stbtt_GetCodepointKernAdvance(font, 'W', 'W');
> +	vc_priv->cols =
> +		(int)VID_TO_POS(vid_priv->xsize - 2) /
> +		(int)VID_TO_POS(advance * priv->scale);
> +	vc_priv->x_charsize = advance * priv->scale;
> +
>   	stbtt_GetFontVMetrics(font, &ascent, 0, 0);
>   	priv->baseline = (int)(ascent * priv->scale);
>   	debug("%s: ready\n", __func__);
> diff --git a/include/video_console.h b/include/video_console.h
> index 06b798ef10..6ec9b4c5b0 100644
> --- a/include/video_console.h
> +++ b/include/video_console.h
> @@ -68,7 +68,7 @@ struct vidconsole_priv {
>   	int ycur;
>   	int rows;
>   	int cols;
> -	int x_charsize;
> +	double x_charsize;
>   	int y_charsize;
>   	int tab_width_frac;
>   	int xsize_frac;
> diff --git a/test/dm/video.c b/test/dm/video.c
> index 1d29b2d61c..c0ad83521a 100644
> --- a/test/dm/video.c
> +++ b/test/dm/video.c
> @@ -344,7 +344,7 @@ static int dm_test_video_truetype(struct unit_test_state *uts)
>   	ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
>   	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
>   	vidconsole_put_string(con, test_string);
> -	ut_asserteq(13001, compress_frame_buffer(uts, dev));
> +	ut_asserteq(12752, compress_frame_buffer(uts, dev));
>
>   	return 0;
>   }
> @@ -365,7 +365,7 @@ static int dm_test_video_truetype_scroll(struct unit_test_state *uts)
>   	ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
>   	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
>   	vidconsole_put_string(con, test_string);
> -	ut_asserteq(36952, compress_frame_buffer(uts, dev));
> +	ut_asserteq(36493, compress_frame_buffer(uts, dev));
>
>   	return 0;
>   }
> @@ -386,7 +386,7 @@ static int dm_test_video_truetype_bs(struct unit_test_state *uts)
>   	ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
>   	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
>   	vidconsole_put_string(con, test_string);
> -	ut_asserteq(30747, compress_frame_buffer(uts, dev));
> +	ut_asserteq(31117, compress_frame_buffer(uts, dev));
>
>   	return 0;
>   }
> --
> 2.30.2
>
diff mbox series

Patch

diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c
index d9ad52cce0..6fe238eab3 100644
--- a/drivers/video/console_truetype.c
+++ b/drivers/video/console_truetype.c
@@ -209,7 +209,7 @@  static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y,
 	int width_frac, linenum;
 	struct pos_info *pos;
 	u8 *bits, *data;
-	int advance;
+	int advance, kern_adv;
 	void *start, *line, *sync_start, *sync_end;
 	int row, ret;
 	int bg_r, bg_g, bg_b;
@@ -224,8 +224,11 @@  static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y,
 	 * this character */
 	xpos = frac(VID_TO_PIXEL((double)x));
 	if (vc_priv->last_ch) {
-		xpos += priv->scale * stbtt_GetCodepointKernAdvance(font,
-							vc_priv->last_ch, ch);
+		kern_adv = stbtt_GetCodepointKernAdvance(font, vc_priv->last_ch,
+							 ch);
+		xpos += priv->scale * kern_adv;
+	} else {
+		kern_adv = 0;
 	}

 	/*
@@ -236,8 +239,8 @@  static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y,
 	 */
 	x_shift = xpos - (double)tt_floor(xpos);
 	xpos += advance * priv->scale;
-	width_frac = (int)VID_TO_POS(xpos);
-	if (x + width_frac >= vc_priv->xsize_frac)
+	width_frac = VID_TO_POS(priv->scale * (kern_adv + advance));
+	if (x + (int)VID_TO_POS(xpos) >= vc_priv->xsize_frac)
 		return -EAGAIN;

 	/* Write the current cursor position into history */
@@ -585,20 +588,21 @@  static int console_truetype_probe(struct udevice *dev)
 	struct udevice *vid_dev = dev->parent;
 	struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev);
 	stbtt_fontinfo *font = &priv->font;
-	int ascent;
+	int advance, ascent, lsb;

 	debug("%s: start\n", __func__);
+
 	if (vid_priv->font_size)
 		priv->font_size = vid_priv->font_size;
 	else
 		priv->font_size = CONFIG_CONSOLE_TRUETYPE_SIZE;
+
 	priv->font_data = console_truetype_find_font();
 	if (!priv->font_data) {
 		debug("%s: Could not find any fonts\n", __func__);
 		return -EBFONT;
 	}

-	vc_priv->x_charsize = priv->font_size;
 	vc_priv->y_charsize = priv->font_size;
 	vc_priv->xstart_frac = VID_TO_POS(2);
 	vc_priv->cols = vid_priv->xsize / priv->font_size;
@@ -612,6 +616,15 @@  static int console_truetype_probe(struct udevice *dev)

 	/* Pre-calculate some things we will need regularly */
 	priv->scale = stbtt_ScaleForPixelHeight(font, priv->font_size);
+
+	/* Assuming that 'W' is the widest character */
+	stbtt_GetCodepointHMetrics(font, 'W', &advance, &lsb);
+	advance += stbtt_GetCodepointKernAdvance(font, 'W', 'W');
+	vc_priv->cols =
+		(int)VID_TO_POS(vid_priv->xsize - 2) /
+		(int)VID_TO_POS(advance * priv->scale);
+	vc_priv->x_charsize = advance * priv->scale;
+
 	stbtt_GetFontVMetrics(font, &ascent, 0, 0);
 	priv->baseline = (int)(ascent * priv->scale);
 	debug("%s: ready\n", __func__);
diff --git a/include/video_console.h b/include/video_console.h
index 06b798ef10..6ec9b4c5b0 100644
--- a/include/video_console.h
+++ b/include/video_console.h
@@ -68,7 +68,7 @@  struct vidconsole_priv {
 	int ycur;
 	int rows;
 	int cols;
-	int x_charsize;
+	double x_charsize;
 	int y_charsize;
 	int tab_width_frac;
 	int xsize_frac;
diff --git a/test/dm/video.c b/test/dm/video.c
index 1d29b2d61c..c0ad83521a 100644
--- a/test/dm/video.c
+++ b/test/dm/video.c
@@ -344,7 +344,7 @@  static int dm_test_video_truetype(struct unit_test_state *uts)
 	ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
 	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
 	vidconsole_put_string(con, test_string);
-	ut_asserteq(13001, compress_frame_buffer(uts, dev));
+	ut_asserteq(12752, compress_frame_buffer(uts, dev));

 	return 0;
 }
@@ -365,7 +365,7 @@  static int dm_test_video_truetype_scroll(struct unit_test_state *uts)
 	ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
 	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
 	vidconsole_put_string(con, test_string);
-	ut_asserteq(36952, compress_frame_buffer(uts, dev));
+	ut_asserteq(36493, compress_frame_buffer(uts, dev));

 	return 0;
 }
@@ -386,7 +386,7 @@  static int dm_test_video_truetype_bs(struct unit_test_state *uts)
 	ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
 	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
 	vidconsole_put_string(con, test_string);
-	ut_asserteq(30747, compress_frame_buffer(uts, dev));
+	ut_asserteq(31117, compress_frame_buffer(uts, dev));

 	return 0;
 }