video: Refactor to allow more than one font size

At present the truetype console supports only a single font and size. It
is useful to be able to support different combinations. As a first step,
move the metrics into there own structure and allow having multiple
metrics.

Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass 2022-10-06 08:36:11 -06:00 committed by Anatolij Gustschin
parent 5330612f21
commit 31efa25095
2 changed files with 113 additions and 42 deletions

View file

@ -176,6 +176,21 @@ config CONSOLE_TRUETYPE_SIZE
method to select the display's physical size, which would allow method to select the display's physical size, which would allow
U-Boot to calculate the correct font size. U-Boot to calculate the correct font size.
config CONSOLE_TRUETYPE_MAX_METRICS
int "TrueType maximum number of font / size combinations"
depends on CONSOLE_TRUETYPE
default 10 if EXPO
default 1
help
This sets the number of font / size combinations which can be used by
the console. For simple console use a single font is enough. When
boot menus are in use, this may need to be increased.
Note that a separate entry is needed for each font size, even if the
font itself is the same. This is because the entry caches various
font metrics which are expensive to regenerate each time the font
size changes.
config SYS_WHITE_ON_BLACK config SYS_WHITE_ON_BLACK
bool "Display console as white on a black background" bool "Display console as white on a black background"
default y if ARCH_AT91 || ARCH_EXYNOS || ARCH_ROCKCHIP || ARCH_TEGRA || X86 || ARCH_SUNXI default y if ARCH_AT91 || ARCH_EXYNOS || ARCH_ROCKCHIP || ARCH_TEGRA || X86 || ARCH_SUNXI

View file

@ -94,17 +94,15 @@ struct pos_info {
#define POS_HISTORY_SIZE (CONFIG_SYS_CBSIZE * 11 / 10) #define POS_HISTORY_SIZE (CONFIG_SYS_CBSIZE * 11 / 10)
/** /**
* struct console_tt_priv - Private data for this driver * struct console_tt_metrics - Information about a font / size combination
*
* This caches various font metrics which are expensive to regenerate each time
* the font size changes. There is one of these for each font / size combination
* that is being used
* *
* @font_size: Vertical font size in pixels * @font_size: Vertical font size in pixels
* @font_data: Pointer to TrueType font file contents * @font_data: Pointer to TrueType font file contents
* @font: TrueType font information for the current font * @font: TrueType font information for the current font
* @pos: List of cursor positions for each character written. This is
* used to handle backspace. We clear the frame buffer between
* the last position and the current position, thus erasing the
* last character. We record enough characters to go back to the
* start of the current command line.
* @pos_ptr: Current position in the position history
* @baseline: Pixel offset of the font's baseline from the cursor position. * @baseline: Pixel offset of the font's baseline from the cursor position.
* This is the 'ascent' of the font, scaled to pixel coordinates. * This is the 'ascent' of the font, scaled to pixel coordinates.
* It measures the distance from the baseline to the top of the * It measures the distance from the baseline to the top of the
@ -113,25 +111,45 @@ struct pos_info {
* of the font. It is used by the STB library to generate images * of the font. It is used by the STB library to generate images
* of the correct size. * of the correct size.
*/ */
struct console_tt_priv { struct console_tt_metrics {
int font_size; int font_size;
u8 *font_data; const u8 *font_data;
stbtt_fontinfo font; stbtt_fontinfo font;
struct pos_info pos[POS_HISTORY_SIZE];
int pos_ptr;
int baseline; int baseline;
double scale; double scale;
}; };
/**
* struct console_tt_priv - Private data for this driver
*
* @cur_met: Current metrics being used
* @metrics: List metrics that can be used
* @num_metrics: Number of available metrics
* @pos: List of cursor positions for each character written. This is
* used to handle backspace. We clear the frame buffer between
* the last position and the current position, thus erasing the
* last character. We record enough characters to go back to the
* start of the current command line.
* @pos_ptr: Current position in the position history
*/
struct console_tt_priv {
struct console_tt_metrics *cur_met;
struct console_tt_metrics metrics[CONFIG_CONSOLE_TRUETYPE_MAX_METRICS];
int num_metrics;
struct pos_info pos[POS_HISTORY_SIZE];
int pos_ptr;
};
static int console_truetype_set_row(struct udevice *dev, uint row, int clr) 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 video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
struct console_tt_priv *priv = dev_get_priv(dev); struct console_tt_priv *priv = dev_get_priv(dev);
struct console_tt_metrics *met = priv->cur_met;
void *end, *line; void *end, *line;
int ret; int ret;
line = vid_priv->fb + row * priv->font_size * vid_priv->line_length; line = vid_priv->fb + row * met->font_size * vid_priv->line_length;
end = line + priv->font_size * vid_priv->line_length; end = line + met->font_size * vid_priv->line_length;
switch (vid_priv->bpix) { switch (vid_priv->bpix) {
#ifdef CONFIG_VIDEO_BPP8 #ifdef CONFIG_VIDEO_BPP8
@ -176,19 +194,20 @@ static int console_truetype_move_rows(struct udevice *dev, uint rowdst,
{ {
struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent); struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
struct console_tt_priv *priv = dev_get_priv(dev); struct console_tt_priv *priv = dev_get_priv(dev);
struct console_tt_metrics *met = priv->cur_met;
void *dst; void *dst;
void *src; void *src;
int i, diff, ret; int i, diff, ret;
dst = vid_priv->fb + rowdst * priv->font_size * vid_priv->line_length; dst = vid_priv->fb + rowdst * met->font_size * vid_priv->line_length;
src = vid_priv->fb + rowsrc * priv->font_size * vid_priv->line_length; src = vid_priv->fb + rowsrc * met->font_size * vid_priv->line_length;
ret = vidconsole_memmove(dev, dst, src, priv->font_size * ret = vidconsole_memmove(dev, dst, src, met->font_size *
vid_priv->line_length * count); vid_priv->line_length * count);
if (ret) if (ret)
return ret; return ret;
/* Scroll up our position history */ /* Scroll up our position history */
diff = (rowsrc - rowdst) * priv->font_size; diff = (rowsrc - rowdst) * met->font_size;
for (i = 0; i < priv->pos_ptr; i++) for (i = 0; i < priv->pos_ptr; i++)
priv->pos[i].ypos -= diff; priv->pos[i].ypos -= diff;
@ -202,7 +221,8 @@ static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y,
struct udevice *vid = dev->parent; struct udevice *vid = dev->parent;
struct video_priv *vid_priv = dev_get_uclass_priv(vid); struct video_priv *vid_priv = dev_get_uclass_priv(vid);
struct console_tt_priv *priv = dev_get_priv(dev); struct console_tt_priv *priv = dev_get_priv(dev);
stbtt_fontinfo *font = &priv->font; struct console_tt_metrics *met = priv->cur_met;
stbtt_fontinfo *font = &met->font;
int width, height, xoff, yoff; int width, height, xoff, yoff;
double xpos, x_shift; double xpos, x_shift;
int lsb; int lsb;
@ -222,7 +242,7 @@ static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y,
* this character */ * this character */
xpos = frac(VID_TO_PIXEL((double)x)); xpos = frac(VID_TO_PIXEL((double)x));
if (vc_priv->last_ch) { if (vc_priv->last_ch) {
xpos += priv->scale * stbtt_GetCodepointKernAdvance(font, xpos += met->scale * stbtt_GetCodepointKernAdvance(font,
vc_priv->last_ch, ch); vc_priv->last_ch, ch);
} }
@ -233,7 +253,7 @@ static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y,
* it dictates how much the cursor will move forward on the line. * it dictates how much the cursor will move forward on the line.
*/ */
x_shift = xpos - (double)tt_floor(xpos); x_shift = xpos - (double)tt_floor(xpos);
xpos += advance * priv->scale; xpos += advance * met->scale;
width_frac = (int)VID_TO_POS(xpos); width_frac = (int)VID_TO_POS(xpos);
if (x + width_frac >= vc_priv->xsize_frac) if (x + width_frac >= vc_priv->xsize_frac)
return -EAGAIN; return -EAGAIN;
@ -252,7 +272,7 @@ static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y,
* image of the character. For empty characters, like ' ', data will * image of the character. For empty characters, like ' ', data will
* return NULL; * return NULL;
*/ */
data = stbtt_GetCodepointBitmapSubpixel(font, priv->scale, priv->scale, data = stbtt_GetCodepointBitmapSubpixel(font, met->scale, met->scale,
x_shift, 0, ch, &width, &height, x_shift, 0, ch, &width, &height,
&xoff, &yoff); &xoff, &yoff);
if (!data) if (!data)
@ -262,7 +282,7 @@ static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y,
bits = data; bits = data;
start = vid_priv->fb + y * vid_priv->line_length + start = vid_priv->fb + y * vid_priv->line_length +
VID_TO_PIXEL(x) * VNBYTES(vid_priv->bpix); VID_TO_PIXEL(x) * VNBYTES(vid_priv->bpix);
linenum = priv->baseline + yoff; linenum = met->baseline + yoff;
if (linenum > 0) if (linenum > 0)
start += linenum * vid_priv->line_length; start += linenum * vid_priv->line_length;
line = start; line = start;
@ -562,42 +582,78 @@ static u8 *console_truetype_find_font(void)
return NULL; return NULL;
} }
/**
* vidconsole_add_metrics() - Add a new font/size combination
*
* @dev: Video console device to update
* @font_name: Name of font
* @font_size: Size of the font (norminal pixel height)
* @font_data: Pointer to the font data
* @return 0 if OK, -EPERM if stbtt failed, -E2BIG if the the metrics table is
* full
*/
static int vidconsole_add_metrics(struct udevice *dev, const void *font_data,
uint font_size)
{
struct console_tt_priv *priv = dev_get_priv(dev);
struct console_tt_metrics *met;
stbtt_fontinfo *font;
int ascent;
if (priv->num_metrics == CONFIG_CONSOLE_TRUETYPE_MAX_METRICS)
return log_msg_ret("num", -E2BIG);
met = &priv->metrics[priv->num_metrics];
met->font_size = font_size;
met->font_data = font_data;
font = &met->font;
if (!stbtt_InitFont(font, font_data, 0)) {
debug("%s: Font init failed\n", __func__);
return -EPERM;
}
/* Pre-calculate some things we will need regularly */
met->scale = stbtt_ScaleForPixelHeight(font, font_size);
stbtt_GetFontVMetrics(font, &ascent, 0, 0);
met->baseline = (int)(ascent * met->scale);
return priv->num_metrics++;
}
static int console_truetype_probe(struct udevice *dev) static int console_truetype_probe(struct udevice *dev)
{ {
struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev); struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
struct console_tt_priv *priv = dev_get_priv(dev); struct console_tt_priv *priv = dev_get_priv(dev);
struct udevice *vid_dev = dev->parent; struct udevice *vid_dev = dev->parent;
struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev); struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev);
stbtt_fontinfo *font = &priv->font; void *font_data;
int ascent; uint font_size;
int ret;
debug("%s: start\n", __func__); debug("%s: start\n", __func__);
if (vid_priv->font_size) if (vid_priv->font_size)
priv->font_size = vid_priv->font_size; font_size = vid_priv->font_size;
else else
priv->font_size = CONFIG_CONSOLE_TRUETYPE_SIZE; font_size = CONFIG_CONSOLE_TRUETYPE_SIZE;
priv->font_data = console_truetype_find_font(); font_data = console_truetype_find_font();
if (!priv->font_data) { if (!font_data) {
debug("%s: Could not find any fonts\n", __func__); debug("%s: Could not find any fonts\n", __func__);
return -EBFONT; return -EBFONT;
} }
vc_priv->x_charsize = priv->font_size; ret = vidconsole_add_metrics(dev, font_data, font_size);
vc_priv->y_charsize = priv->font_size; if (ret < 0)
return log_msg_ret("add", ret);
priv->cur_met = &priv->metrics[ret];
vc_priv->x_charsize = font_size;
vc_priv->y_charsize = font_size;
vc_priv->xstart_frac = VID_TO_POS(2); vc_priv->xstart_frac = VID_TO_POS(2);
vc_priv->cols = vid_priv->xsize / priv->font_size; vc_priv->cols = vid_priv->xsize / font_size;
vc_priv->rows = vid_priv->ysize / priv->font_size; vc_priv->rows = vid_priv->ysize / font_size;
vc_priv->tab_width_frac = VID_TO_POS(priv->font_size) * 8 / 2; vc_priv->tab_width_frac = VID_TO_POS(font_size) * 8 / 2;
if (!stbtt_InitFont(font, priv->font_data, 0)) {
debug("%s: Font init failed\n", __func__);
return -EPERM;
}
/* Pre-calculate some things we will need regularly */
priv->scale = stbtt_ScaleForPixelHeight(font, priv->font_size);
stbtt_GetFontVMetrics(font, &ascent, 0, 0);
priv->baseline = (int)(ascent * priv->scale);
debug("%s: ready\n", __func__); debug("%s: ready\n", __func__);
return 0; return 0;