2 * Copyright (c) 2016 Google, Inc
4 * SPDX-License-Identifier: GPL-2.0+
10 #include <video_console.h>
12 /* Functions needed by stb_truetype.h */
13 static int tt_floor(double val
)
16 return (int)(val
- 0.999);
21 static int tt_ceil(double val
)
26 return (int)(val
+ 0.999);
29 static double frac(double val
)
31 return val
- tt_floor(val
);
34 static double tt_fabs(double x
)
36 return x
< 0 ? -x
: x
;
40 * Simple square root algorithm. This is from:
41 * http://stackoverflow.com/questions/1623375/writing-your-own-square-root-function
42 * Written by Chihung Yu
43 * Creative Commons license
44 * http://creativecommons.org/licenses/by-sa/3.0/legalcode
45 * It has been modified to compile correctly, and for U-Boot style.
47 static double tt_sqrt(double value
)
52 while (hi
- lo
> 0.00001) {
53 double mid
= lo
+ (hi
- lo
) / 2;
55 if (mid
* mid
- value
> 0.00001)
64 #define STBTT_ifloor tt_floor
65 #define STBTT_iceil tt_ceil
66 #define STBTT_fabs tt_fabs
67 #define STBTT_sqrt tt_sqrt
68 #define STBTT_malloc(size, u) ((void)(u), malloc(size))
69 #define STBTT_free(size, u) ((void)(u), free(size))
70 #define STBTT_assert(x)
71 #define STBTT_strlen(x) strlen(x)
72 #define STBTT_memcpy memcpy
73 #define STBTT_memset memset
75 #define STB_TRUETYPE_IMPLEMENTATION
76 #include "stb_truetype.h"
79 * struct pos_info - Records a cursor position
81 * @xpos_frac: Fractional X position in pixels (multiplied by VID_FRAC_DIV)
82 * @ypos: Y position (pixels from the top)
90 * Allow one for each character on the command line plus one for each newline.
91 * This is just an estimate, but it should not be exceeded.
93 #define POS_HISTORY_SIZE (CONFIG_SYS_CBSIZE * 11 / 10)
96 * struct console_tt_priv - Private data for this driver
98 * @font_size: Vertical font size in pixels
99 * @font_data: Pointer to TrueType font file contents
100 * @font: TrueType font information for the current font
101 * @pos: List of cursor positions for each character written. This is
102 * used to handle backspace. We clear the frame buffer between
103 * the last position and the current position, thus erasing the
104 * last character. We record enough characters to go back to the
105 * start of the current command line.
106 * @pos_ptr: Current position in the position history
107 * @baseline: Pixel offset of the font's baseline from the cursor position.
108 * This is the 'ascent' of the font, scaled to pixel coordinates.
109 * It measures the distance from the baseline to the top of the
111 * @scale: Scale of the font. This is calculated from the pixel height
112 * of the font. It is used by the STB library to generate images
113 * of the correct size.
115 struct console_tt_priv
{
119 struct pos_info pos
[POS_HISTORY_SIZE
];
125 static int console_truetype_set_row(struct udevice
*dev
, uint row
, int clr
)
127 struct video_priv
*vid_priv
= dev_get_uclass_priv(dev
->parent
);
128 struct console_tt_priv
*priv
= dev_get_priv(dev
);
130 int pixels
= priv
->font_size
* vid_priv
->line_length
;
133 line
= vid_priv
->fb
+ row
* priv
->font_size
* vid_priv
->line_length
;
134 switch (vid_priv
->bpix
) {
135 #ifdef CONFIG_VIDEO_BPP8
139 for (i
= 0; i
< pixels
; i
++)
144 #ifdef CONFIG_VIDEO_BPP16
146 uint16_t *dst
= line
;
148 for (i
= 0; i
< pixels
; i
++)
153 #ifdef CONFIG_VIDEO_BPP32
155 uint32_t *dst
= line
;
157 for (i
= 0; i
< pixels
; i
++)
169 static int console_truetype_move_rows(struct udevice
*dev
, uint rowdst
,
170 uint rowsrc
, uint count
)
172 struct video_priv
*vid_priv
= dev_get_uclass_priv(dev
->parent
);
173 struct console_tt_priv
*priv
= dev_get_priv(dev
);
178 dst
= vid_priv
->fb
+ rowdst
* priv
->font_size
* vid_priv
->line_length
;
179 src
= vid_priv
->fb
+ rowsrc
* priv
->font_size
* vid_priv
->line_length
;
180 memmove(dst
, src
, priv
->font_size
* vid_priv
->line_length
* count
);
182 /* Scroll up our position history */
183 diff
= (rowsrc
- rowdst
) * priv
->font_size
;
184 for (i
= 0; i
< priv
->pos_ptr
; i
++)
185 priv
->pos
[i
].ypos
-= diff
;
190 static int console_truetype_putc_xy(struct udevice
*dev
, uint x
, uint y
,
193 struct vidconsole_priv
*vc_priv
= dev_get_uclass_priv(dev
);
194 struct udevice
*vid
= dev
->parent
;
195 struct video_priv
*vid_priv
= dev_get_uclass_priv(vid
);
196 struct console_tt_priv
*priv
= dev_get_priv(dev
);
197 stbtt_fontinfo
*font
= &priv
->font
;
198 int width
, height
, xoff
, yoff
;
199 double xpos
, x_shift
;
201 int width_frac
, linenum
;
202 struct pos_info
*pos
;
208 /* First get some basic metrics about this character */
209 stbtt_GetCodepointHMetrics(font
, ch
, &advance
, &lsb
);
212 * First out our current X position in fractional pixels. If we wrote
213 * a character previously, using kerning to fine-tune the position of
215 xpos
= frac(VID_TO_PIXEL((double)x
));
216 if (vc_priv
->last_ch
) {
217 xpos
+= priv
->scale
* stbtt_GetCodepointKernAdvance(font
,
218 vc_priv
->last_ch
, ch
);
222 * Figure out where the cursor will move to after this character, and
223 * abort if we are out of space on this line. Also calculate the
224 * effective width of this character, which will be our return value:
225 * it dictates how much the cursor will move forward on the line.
227 x_shift
= xpos
- (double)tt_floor(xpos
);
228 xpos
+= advance
* priv
->scale
;
229 width_frac
= (int)VID_TO_POS(xpos
);
230 if (x
+ width_frac
>= vc_priv
->xsize_frac
)
233 /* Write the current cursor position into history */
234 if (priv
->pos_ptr
< POS_HISTORY_SIZE
) {
235 pos
= &priv
->pos
[priv
->pos_ptr
];
236 pos
->xpos_frac
= vc_priv
->xcur_frac
;
237 pos
->ypos
= vc_priv
->ycur
;
242 * Figure out how much past the start of a pixel we are, and pass this
243 * information into the render, which will return a 8-bit-per-pixel
244 * image of the character. For empty characters, like ' ', data will
247 data
= stbtt_GetCodepointBitmapSubpixel(font
, priv
->scale
, priv
->scale
,
248 x_shift
, 0, ch
, &width
, &height
,
253 /* Figure out where to write the character in the frame buffer */
255 line
= vid_priv
->fb
+ y
* vid_priv
->line_length
+
256 VID_TO_PIXEL(x
) * VNBYTES(vid_priv
->bpix
);
257 linenum
= priv
->baseline
+ yoff
;
259 line
+= linenum
* vid_priv
->line_length
;
262 * Write a row at a time, converting the 8bpp image into the colour
263 * depth of the display. We only expect white-on-black or the reverse
264 * so the code only handles this simple case.
266 for (row
= 0; row
< height
; row
++) {
267 switch (vid_priv
->bpix
) {
268 #ifdef CONFIG_VIDEO_BPP16
270 uint16_t *dst
= (uint16_t *)line
+ xoff
;
273 for (i
= 0; i
< width
; i
++) {
277 if (vid_priv
->colour_bg
)
282 if (vid_priv
->colour_fg
)
296 line
+= vid_priv
->line_length
;
304 * console_truetype_erase() - Erase a character
306 * This is used for backspace. We erase a square of the display within the
309 * @dev: Device to update
310 * @xstart: X start position in pixels from the left
311 * @ystart: Y start position in pixels from the top
312 * @xend: X end position in pixels from the left
313 * @yend: Y end position in pixels from the top
314 * @clr: Value to write
315 * @return 0 if OK, -ENOSYS if the display depth is not supported
317 static int console_truetype_erase(struct udevice
*dev
, int xstart
, int ystart
,
318 int xend
, int yend
, int clr
)
320 struct video_priv
*vid_priv
= dev_get_uclass_priv(dev
->parent
);
322 int pixels
= xend
- xstart
;
325 line
= vid_priv
->fb
+ ystart
* vid_priv
->line_length
;
326 line
+= xstart
* VNBYTES(vid_priv
->bpix
);
327 for (row
= ystart
; row
< yend
; row
++) {
328 switch (vid_priv
->bpix
) {
329 #ifdef CONFIG_VIDEO_BPP8
333 for (i
= 0; i
< pixels
; i
++)
338 #ifdef CONFIG_VIDEO_BPP16
340 uint16_t *dst
= line
;
342 for (i
= 0; i
< pixels
; i
++)
347 #ifdef CONFIG_VIDEO_BPP32
349 uint32_t *dst
= line
;
351 for (i
= 0; i
< pixels
; i
++)
359 line
+= vid_priv
->line_length
;
366 * console_truetype_backspace() - Handle a backspace operation
368 * This clears the previous character so that the console looks as if it had
371 * @dev: Device to update
372 * @return 0 if OK, -ENOSYS if not supported
374 static int console_truetype_backspace(struct udevice
*dev
)
376 struct vidconsole_priv
*vc_priv
= dev_get_uclass_priv(dev
);
377 struct console_tt_priv
*priv
= dev_get_priv(dev
);
378 struct udevice
*vid_dev
= dev
->parent
;
379 struct video_priv
*vid_priv
= dev_get_uclass_priv(vid_dev
);
380 struct pos_info
*pos
;
384 * This indicates a very strange error higher in the stack. The caller
385 * has sent out n character and n + 1 backspaces.
390 /* Pop the last cursor position off the stack */
391 pos
= &priv
->pos
[--priv
->pos_ptr
];
394 * Figure out the end position for clearing. Normlly it is the current
395 * cursor position, but if we are clearing a character on the previous
396 * line, we clear from the end of the line.
398 if (pos
->ypos
== vc_priv
->ycur
)
399 xend
= VID_TO_PIXEL(vc_priv
->xcur_frac
);
401 xend
= vid_priv
->xsize
;
403 console_truetype_erase(dev
, VID_TO_PIXEL(pos
->xpos_frac
), pos
->ypos
,
404 xend
, pos
->ypos
+ vc_priv
->y_charsize
,
405 vid_priv
->colour_bg
);
407 /* Move the cursor back to where it was when we pushed this record */
408 vc_priv
->xcur_frac
= pos
->xpos_frac
;
409 vc_priv
->ycur
= pos
->ypos
;
414 static int console_truetype_entry_start(struct udevice
*dev
)
416 struct console_tt_priv
*priv
= dev_get_priv(dev
);
418 /* A new input line has start, so clear our history */
425 * Provides a list of fonts which can be obtained at run-time in U-Boot. These
426 * are compiled in by the Makefile.
428 * At present there is no mechanism to select a particular font - the first
429 * one found is the one that is used. But the build system and the code here
430 * supports multiple fonts, which may be useful for certain firmware screens.
438 #define FONT_DECL(_name) \
439 extern u8 __ttf_ ## _name ## _begin[]; \
440 extern u8 __ttf_ ## _name ## _end[];
442 #define FONT_ENTRY(_name) { \
444 .begin = __ttf_ ## _name ## _begin, \
445 .end = __ttf_ ## _name ## _end, \
448 FONT_DECL(nimbus_sans_l_regular
);
449 FONT_DECL(ankacoder_c75_r
);
450 FONT_DECL(rufscript010
);
451 FONT_DECL(cantoraone_regular
);
453 static struct font_info font_table
[] = {
454 #ifdef CONFIG_CONSOLE_TRUETYPE_NIMBUS
455 FONT_ENTRY(nimbus_sans_l_regular
),
457 #ifdef CONFIG_CONSOLE_TRUETYPE_ANKACODER
458 FONT_ENTRY(ankacoder_c75_r
),
460 #ifdef CONFIG_CONSOLE_TRUETYPE_RUFSCRIPT
461 FONT_ENTRY(rufscript010
),
463 #ifdef CONFIG_CONSOLE_TRUETYPE_CANTORAONE
464 FONT_ENTRY(cantoraone_regular
),
469 #define FONT_BEGIN(name) __ttf_ ## name ## _begin
470 #define FONT_END(name) __ttf_ ## name ## _end
471 #define FONT_IS_VALID(name) (abs(FONT_END(name) - FONT_BEGIN) > 4)
474 * console_truetype_find_font() - Find a suitable font
476 * This searched for the first available font.
478 * @return pointer to the font, or NULL if none is found
480 static u8
*console_truetype_find_font(void)
482 struct font_info
*tab
;
484 for (tab
= font_table
; tab
->begin
; tab
++) {
485 if (abs(tab
->begin
- tab
->end
) > 4) {
486 debug("%s: Font '%s', at %p, size %lx\n", __func__
,
487 tab
->name
, tab
->begin
,
488 (ulong
)(tab
->end
- tab
->begin
));
496 static int console_truetype_probe(struct udevice
*dev
)
498 struct vidconsole_priv
*vc_priv
= dev_get_uclass_priv(dev
);
499 struct console_tt_priv
*priv
= dev_get_priv(dev
);
500 struct udevice
*vid_dev
= dev
->parent
;
501 struct video_priv
*vid_priv
= dev_get_uclass_priv(vid_dev
);
502 stbtt_fontinfo
*font
= &priv
->font
;
505 debug("%s: start\n", __func__
);
506 if (vid_priv
->font_size
)
507 priv
->font_size
= vid_priv
->font_size
;
509 priv
->font_size
= CONFIG_CONSOLE_TRUETYPE_SIZE
;
510 priv
->font_data
= console_truetype_find_font();
511 if (!priv
->font_data
) {
512 debug("%s: Could not find any fonts\n", __func__
);
516 vc_priv
->x_charsize
= priv
->font_size
;
517 vc_priv
->y_charsize
= priv
->font_size
;
518 vc_priv
->xstart_frac
= VID_TO_POS(2);
519 vc_priv
->cols
= vid_priv
->xsize
/ priv
->font_size
;
520 vc_priv
->rows
= vid_priv
->ysize
/ priv
->font_size
;
521 vc_priv
->tab_width_frac
= VID_TO_POS(priv
->font_size
) * 8 / 2;
523 if (!stbtt_InitFont(font
, priv
->font_data
, 0)) {
524 debug("%s: Font init failed\n", __func__
);
528 /* Pre-calculate some things we will need regularly */
529 priv
->scale
= stbtt_ScaleForPixelHeight(font
, priv
->font_size
);
530 stbtt_GetFontVMetrics(font
, &ascent
, 0, 0);
531 priv
->baseline
= (int)(ascent
* priv
->scale
);
532 debug("%s: ready\n", __func__
);
537 struct vidconsole_ops console_truetype_ops
= {
538 .putc_xy
= console_truetype_putc_xy
,
539 .move_rows
= console_truetype_move_rows
,
540 .set_row
= console_truetype_set_row
,
541 .backspace
= console_truetype_backspace
,
542 .entry_start
= console_truetype_entry_start
,
545 U_BOOT_DRIVER(vidconsole_truetype
) = {
546 .name
= "vidconsole_tt",
547 .id
= UCLASS_VIDEO_CONSOLE
,
548 .ops
= &console_truetype_ops
,
549 .probe
= console_truetype_probe
,
550 .priv_auto_alloc_size
= sizeof(struct console_tt_priv
),