diff options
Diffstat (limited to 'drivers/video/console_truetype.c')
-rw-r--r-- | drivers/video/console_truetype.c | 140 |
1 files changed, 98 insertions, 42 deletions
diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c index 1331ce8d89..ab7bcda197 100644 --- a/drivers/video/console_truetype.c +++ b/drivers/video/console_truetype.c @@ -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; |