
From: Simon Glass <sjg@chromium.org> Within the CLI, inserting a character works by writing out the new char and then all the ones after it. With the truetype console this results in gibberish since the new chars are written on top of the old. To resolve this, clear the rest of the input when a character is inserted. Consider that the end of the input, at least until furture characters are written. As an optimisation, don't clear if the new character is the same as the old. This cleans up a dot above the 'g' of greatness which should not be there, so update the dm_test_video_truetype() test. It also clean up the part of the 't' of 'not be' which should not be there, so update dm_test_video_truetype_bs() too. Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/video/console_truetype.c | 76 ++++++++++++++++++++++++++++++-- test/dm/video.c | 4 +- 2 files changed, 74 insertions(+), 6 deletions(-) diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c index fc2985ed92f..a42ae318fc8 100644 --- a/drivers/video/console_truetype.c +++ b/drivers/video/console_truetype.c @@ -295,6 +295,58 @@ static int console_truetype_move_rows(struct udevice *dev, uint rowdst, return 0; } +/** + * clear_from() - Clear characters on the display from given index onwards + * + * Erases all characters from the specified position index in the position + * history to the end of the position array (pos_count). This handles line + * wrapping by clearing to the end of lines and continuing on subsequent lines. + * + * @dev: Device to update + * @index: Starting index in priv->pos array to erase from + */ +static void clear_from(struct udevice *dev, int index) +{ + struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev); + struct console_tt_priv *priv = dev_get_priv(dev); + struct udevice *vid_dev = dev->parent; + struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev); + struct pos_info *start_pos, *end_pos; + int xstart, xend; + int ystart, yend; + + assert(priv->pos_count && index && index < priv->pos_count); + + start_pos = &priv->pos[index]; + xstart = VID_TO_PIXEL(start_pos->xpos_frac); + ystart = start_pos->ypos; + + /* End position is the last character in the position array */ + end_pos = &priv->pos[priv->pos_count - 1]; + xend = VID_TO_PIXEL(end_pos->xpos_frac) + end_pos->width; + yend = end_pos->ypos; + + /* If on the same line, just erase from start to end position */ + if (ystart == yend) { + video_fill_part(vid_dev, xstart, ystart, xend, ystart + vc_priv->y_charsize, + vid_priv->colour_bg); + } else { + /* Different lines - erase to end of first line */ + video_fill_part(vid_dev, xstart, ystart, vid_priv->xsize, + ystart + vc_priv->y_charsize, vid_priv->colour_bg); + + /* Erase any complete lines in between */ + if (yend > ystart + vc_priv->y_charsize) { + video_fill_part(vid_dev, 0, ystart + vc_priv->y_charsize, + vid_priv->xsize, yend, vid_priv->colour_bg); + } + + /* Erase from start of final line to end of last character */ + video_fill_part(vid_dev, 0, yend, xend, yend + vc_priv->y_charsize, + vid_priv->colour_bg); + } +} + static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y, int cp) { @@ -326,15 +378,19 @@ static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y, * First out our current X position in fractional pixels. If we wrote * a character previously, use kerning to fine-tune the position of * this character */ + pos = priv->pos_ptr < priv->pos_count ? &priv->pos[priv->pos_ptr] : + NULL; xpos = frac(VID_TO_PIXEL((double)x)); kern = 0; if (vc_priv->last_ch) { - kern = stbtt_GetCodepointKernAdvance(font, vc_priv->last_ch, - cp); + int last_cp = vc_priv->last_ch; + + if (pos) + last_cp = pos->cp; + kern = stbtt_GetCodepointKernAdvance(font, last_cp, cp); if (_DEBUG) { console_printf_select_stderr(true, "kern %c (%02x)", - vc_priv->last_ch, - vc_priv->last_ch); + last_cp, last_cp); } xpos += met->scale * kern; } @@ -357,6 +413,18 @@ static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y, /* Write the current cursor position into history */ if (priv->pos_ptr < POS_HISTORY_SIZE) { + bool erase = false; + + /* Check if we're overwriting a different character */ + if (pos && pos->cp != cp) { + erase = true; + /* Erase using the old character's position before updating */ + clear_from(dev, priv->pos_ptr); + + /* After erasing, we don't care about erased characters */ + priv->pos_count = priv->pos_ptr; + } + pos = &priv->pos[priv->pos_ptr]; pos->xpos_frac = vc_priv->xcur_frac; pos->ypos = vc_priv->ycur; diff --git a/test/dm/video.c b/test/dm/video.c index 3ec12956909..3395fd9f1b3 100644 --- a/test/dm/video.c +++ b/test/dm/video.c @@ -594,7 +594,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(13055, video_compress_fb(uts, dev, false)); + ut_asserteq(13073, video_compress_fb(uts, dev, false)); ut_assertok(video_check_copy_fb(uts, dev)); return 0; @@ -648,7 +648,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(29223, video_compress_fb(uts, dev, false)); + ut_asserteq(29310, video_compress_fb(uts, dev, false)); ut_assertok(video_check_copy_fb(uts, dev)); return 0; -- 2.43.0