video: Refactor to allow more than one font size
authorSimon Glass <sjg@chromium.org>
Thu, 6 Oct 2022 14:36:11 +0000 (08:36 -0600)
committerAnatolij Gustschin <agust@denx.de>
Sun, 30 Oct 2022 19:01:40 +0000 (20:01 +0100)
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>
drivers/video/Kconfig
drivers/video/console_truetype.c

index 44ab9e7..3293837 100644 (file)
@@ -176,6 +176,21 @@ config CONSOLE_TRUETYPE_SIZE
          method to select the display's physical size, which would allow
          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
        bool "Display console as white on a black background"
        default y if ARCH_AT91 || ARCH_EXYNOS || ARCH_ROCKCHIP || ARCH_TEGRA || X86 || ARCH_SUNXI
index 1331ce8..ab7bcda 100644 (file)
@@ -94,17 +94,15 @@ struct pos_info {
 #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_data: Pointer to TrueType font file contents
  * @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.
  *             This is the 'ascent' of the font, scaled to pixel coordinates.
  *             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 correct size.
  */
-struct console_tt_priv {
+struct console_tt_metrics {
        int font_size;
-       u8 *font_data;
+       const u8 *font_data;
        stbtt_fontinfo font;
-       struct pos_info pos[POS_HISTORY_SIZE];
-       int pos_ptr;
        int baseline;
        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)
 {
        struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
        struct console_tt_priv *priv = dev_get_priv(dev);
+       struct console_tt_metrics *met = priv->cur_met;
        void *end, *line;
        int ret;
 
-       line = vid_priv->fb + row * priv->font_size * vid_priv->line_length;
-       end = line + priv->font_size * vid_priv->line_length;
+       line = vid_priv->fb + row * met->font_size * vid_priv->line_length;
+       end = line + met->font_size * vid_priv->line_length;
 
        switch (vid_priv->bpix) {
 #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 console_tt_priv *priv = dev_get_priv(dev);
+       struct console_tt_metrics *met = priv->cur_met;
        void *dst;
        void *src;
        int i, diff, ret;
 
-       dst = vid_priv->fb + rowdst * priv->font_size * vid_priv->line_length;
-       src = vid_priv->fb + rowsrc * priv->font_size * vid_priv->line_length;
-       ret = vidconsole_memmove(dev, dst, src, priv->font_size *
+       dst = vid_priv->fb + rowdst * met->font_size * vid_priv->line_length;
+       src = vid_priv->fb + rowsrc * met->font_size * vid_priv->line_length;
+       ret = vidconsole_memmove(dev, dst, src, met->font_size *
                                 vid_priv->line_length * count);
        if (ret)
                return ret;
 
        /* 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++)
                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 video_priv *vid_priv = dev_get_uclass_priv(vid);
        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;
        double xpos, x_shift;
        int lsb;
@@ -222,7 +242,7 @@ 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,
+               xpos += met->scale * stbtt_GetCodepointKernAdvance(font,
                                                        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.
         */
        x_shift = xpos - (double)tt_floor(xpos);
-       xpos += advance * priv->scale;
+       xpos += advance * met->scale;
        width_frac = (int)VID_TO_POS(xpos);
        if (x + width_frac >= vc_priv->xsize_frac)
                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
         * return NULL;
         */
-       data = stbtt_GetCodepointBitmapSubpixel(font, priv->scale, priv->scale,
+       data = stbtt_GetCodepointBitmapSubpixel(font, met->scale, met->scale,
                                                x_shift, 0, ch, &width, &height,
                                                &xoff, &yoff);
        if (!data)
@@ -262,7 +282,7 @@ static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y,
        bits = data;
        start = vid_priv->fb + y * vid_priv->line_length +
                VID_TO_PIXEL(x) * VNBYTES(vid_priv->bpix);
-       linenum = priv->baseline + yoff;
+       linenum = met->baseline + yoff;
        if (linenum > 0)
                start += linenum * vid_priv->line_length;
        line = start;
@@ -562,42 +582,78 @@ static u8 *console_truetype_find_font(void)
        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)
 {
        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);
-       stbtt_fontinfo *font = &priv->font;
-       int ascent;
+       void *font_data;
+       uint font_size;
+       int ret;
 
        debug("%s: start\n", __func__);
        if (vid_priv->font_size)
-               priv->font_size = vid_priv->font_size;
+               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) {
+               font_size = CONFIG_CONSOLE_TRUETYPE_SIZE;
+       font_data = console_truetype_find_font();
+       if (!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;
-       vc_priv->rows = vid_priv->ysize / priv->font_size;
-       vc_priv->tab_width_frac = VID_TO_POS(priv->font_size) * 8 / 2;
+       ret = vidconsole_add_metrics(dev, font_data, font_size);
+       if (ret < 0)
+               return log_msg_ret("add", ret);
+       priv->cur_met = &priv->metrics[ret];
 
-       if (!stbtt_InitFont(font, priv->font_data, 0)) {
-               debug("%s: Font init failed\n", __func__);
-               return -EPERM;
-       }
+       vc_priv->x_charsize = font_size;
+       vc_priv->y_charsize = font_size;
+       vc_priv->xstart_frac = VID_TO_POS(2);
+       vc_priv->cols = vid_priv->xsize / font_size;
+       vc_priv->rows = vid_priv->ysize / font_size;
+       vc_priv->tab_width_frac = VID_TO_POS(font_size) * 8 / 2;
 
-       /* 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__);
 
        return 0;