aboutsummaryrefslogtreecommitdiff
path: root/drivers/video/console_truetype.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/console_truetype.c')
-rw-r--r--drivers/video/console_truetype.c265
1 files changed, 214 insertions, 51 deletions
diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c
index c04b449a6d..6859c9fa11 100644
--- a/drivers/video/console_truetype.c
+++ b/drivers/video/console_truetype.c
@@ -94,17 +94,16 @@ 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_name: Name of the font
* @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 +112,46 @@ 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 {
+ const char *font_name;
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 +196,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 +223,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 +244,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 +255,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 +274,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 +284,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;
@@ -526,69 +548,210 @@ static struct font_info font_table[] = {
{} /* sentinel */
};
-#define FONT_BEGIN(name) __ttf_ ## name ## _begin
-#define FONT_END(name) __ttf_ ## name ## _end
-#define FONT_IS_VALID(name) (abs(FONT_END(name) - FONT_BEGIN) > 4)
+/**
+ * font_valid() - Check if a font-table entry is valid
+ *
+ * Depending on available files in the build system, fonts may end up being
+ * empty.
+ *
+ * @return true if the entry is valid
+ */
+static inline bool font_valid(struct font_info *tab)
+{
+ return abs(tab->begin - tab->end) > 4;
+}
/**
* console_truetype_find_font() - Find a suitable font
*
- * This searched for the first available font.
+ * This searches for the first available font.
*
- * Return: pointer to the font, or NULL if none is found
+ * Return: pointer to the font-table entry, or NULL if none is found
*/
-static u8 *console_truetype_find_font(void)
+static struct font_info *console_truetype_find_font(void)
{
struct font_info *tab;
for (tab = font_table; tab->begin; tab++) {
- if (abs(tab->begin - tab->end) > 4) {
+ if (font_valid(tab)) {
debug("%s: Font '%s', at %p, size %lx\n", __func__,
tab->name, tab->begin,
(ulong)(tab->end - tab->begin));
- return tab->begin;
+ return tab;
}
}
return NULL;
}
-static int console_truetype_probe(struct udevice *dev)
+void vidconsole_list_fonts(void)
+{
+ struct font_info *tab;
+
+ for (tab = font_table; tab->begin; tab++) {
+ if (abs(tab->begin - tab->end) > 4)
+ printf("%s\n", tab->name);
+ }
+}
+
+/**
+ * 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 char *font_name,
+ uint font_size, const void *font_data)
+{
+ 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_name = font_name;
+ 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++;
+}
+
+/**
+ * find_metrics() - Find the metrics for a given font and size
+ *
+ * @dev: Video console device to update
+ * @name: Name of font
+ * @size: Size of the font (norminal pixel height)
+ * @return metrics, if found, else NULL
+ */
+static struct console_tt_metrics *find_metrics(struct udevice *dev,
+ const char *name, uint size)
+{
+ struct console_tt_priv *priv = dev_get_priv(dev);
+ int i;
+
+ for (i = 0; i < priv->num_metrics; i++) {
+ struct console_tt_metrics *met = &priv->metrics[i];
+
+ if (!strcmp(name, met->font_name) && met->font_size == size)
+ return met;
+ }
+
+ return NULL;
+}
+
+static void select_metrics(struct udevice *dev, struct console_tt_metrics *met)
{
struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
struct console_tt_priv *priv = dev_get_priv(dev);
+ struct udevice *vid_dev = dev_get_parent(dev);
+ struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev);
+
+ priv->cur_met = met;
+ vc_priv->x_charsize = met->font_size;
+ vc_priv->y_charsize = met->font_size;
+ vc_priv->xstart_frac = VID_TO_POS(2);
+ vc_priv->cols = vid_priv->xsize / met->font_size;
+ vc_priv->rows = vid_priv->ysize / met->font_size;
+ vc_priv->tab_width_frac = VID_TO_POS(met->font_size) * 8 / 2;
+}
+
+int vidconsole_select_font(struct udevice *dev, const char *name, uint size)
+{
+ struct console_tt_priv *priv = dev_get_priv(dev);
+ struct console_tt_metrics *met;
+ struct font_info *tab;
+
+ if (name || size) {
+ if (!size)
+ size = CONFIG_CONSOLE_TRUETYPE_SIZE;
+ if (!name)
+ name = priv->cur_met->font_name;
+
+ met = find_metrics(dev, name, size);
+ if (!met) {
+ for (tab = font_table; tab->begin; tab++) {
+ if (font_valid(tab) &&
+ !strcmp(name, tab->name)) {
+ int ret;
+
+ ret = vidconsole_add_metrics(dev,
+ tab->name, size, tab->begin);
+ if (ret < 0)
+ return log_msg_ret("add", ret);
+
+ met = &priv->metrics[ret];
+ break;
+ }
+ }
+ }
+ if (!met)
+ return log_msg_ret("find", -ENOENT);
+ } else {
+ /* Use the default font */
+ met = priv->metrics;
+ }
+
+ select_metrics(dev, met);
+
+ return 0;
+}
+
+const char *vidconsole_get_font(struct udevice *dev, uint *sizep)
+{
+ struct console_tt_priv *priv = dev_get_priv(dev);
+ struct console_tt_metrics *met = priv->cur_met;
+
+ *sizep = met->font_size;
+
+ return met->font_name;
+}
+
+static int console_truetype_probe(struct udevice *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;
+ struct font_info *tab;
+ 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;
+ tab = console_truetype_find_font();
+ if (!tab) {
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, tab->name, font_size, tab->begin);
+ 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;
- }
+ select_metrics(dev, &priv->metrics[ret]);
- /* 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;