console_truetype.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. /*
  2. * Copyright (c) 2016 Google, Inc
  3. *
  4. * SPDX-License-Identifier: GPL-2.0+
  5. */
  6. #include <common.h>
  7. #include <dm.h>
  8. #include <video.h>
  9. #include <video_console.h>
  10. /* Functions needed by stb_truetype.h */
  11. static int tt_floor(double val)
  12. {
  13. if (val < 0)
  14. return (int)(val - 0.999);
  15. return (int)val;
  16. }
  17. static int tt_ceil(double val)
  18. {
  19. if (val < 0)
  20. return (int)val;
  21. return (int)(val + 0.999);
  22. }
  23. static double frac(double val)
  24. {
  25. return val - tt_floor(val);
  26. }
  27. static double tt_fabs(double x)
  28. {
  29. return x < 0 ? -x : x;
  30. }
  31. /*
  32. * Simple square root algorithm. This is from:
  33. * http://stackoverflow.com/questions/1623375/writing-your-own-square-root-function
  34. * Written by Chihung Yu
  35. * Creative Commons license
  36. * http://creativecommons.org/licenses/by-sa/3.0/legalcode
  37. * It has been modified to compile correctly, and for U-Boot style.
  38. */
  39. static double tt_sqrt(double value)
  40. {
  41. double lo = 1.0;
  42. double hi = value;
  43. while (hi - lo > 0.00001) {
  44. double mid = lo + (hi - lo) / 2;
  45. if (mid * mid - value > 0.00001)
  46. hi = mid;
  47. else
  48. lo = mid;
  49. }
  50. return lo;
  51. }
  52. #define STBTT_ifloor tt_floor
  53. #define STBTT_iceil tt_ceil
  54. #define STBTT_fabs tt_fabs
  55. #define STBTT_sqrt tt_sqrt
  56. #define STBTT_malloc(size, u) ((void)(u), malloc(size))
  57. #define STBTT_free(size, u) ((void)(u), free(size))
  58. #define STBTT_assert(x)
  59. #define STBTT_strlen(x) strlen(x)
  60. #define STBTT_memcpy memcpy
  61. #define STBTT_memset memset
  62. #define STB_TRUETYPE_IMPLEMENTATION
  63. #include "stb_truetype.h"
  64. /**
  65. * struct pos_info - Records a cursor position
  66. *
  67. * @xpos_frac: Fractional X position in pixels (multiplied by VID_FRAC_DIV)
  68. * @ypos: Y position (pixels from the top)
  69. */
  70. struct pos_info {
  71. int xpos_frac;
  72. int ypos;
  73. };
  74. /*
  75. * Allow one for each character on the command line plus one for each newline.
  76. * This is just an estimate, but it should not be exceeded.
  77. */
  78. #define POS_HISTORY_SIZE (CONFIG_SYS_CBSIZE * 11 / 10)
  79. /**
  80. * struct console_tt_priv - Private data for this driver
  81. *
  82. * @font_size: Vertical font size in pixels
  83. * @font_data: Pointer to TrueType font file contents
  84. * @font: TrueType font information for the current font
  85. * @pos: List of cursor positions for each character written. This is
  86. * used to handle backspace. We clear the frame buffer between
  87. * the last position and the current position, thus erasing the
  88. * last character. We record enough characters to go back to the
  89. * start of the current command line.
  90. * @pos_ptr: Current position in the position history
  91. * @baseline: Pixel offset of the font's baseline from the cursor position.
  92. * This is the 'ascent' of the font, scaled to pixel coordinates.
  93. * It measures the distance from the baseline to the top of the
  94. * font.
  95. * @scale: Scale of the font. This is calculated from the pixel height
  96. * of the font. It is used by the STB library to generate images
  97. * of the correct size.
  98. */
  99. struct console_tt_priv {
  100. int font_size;
  101. u8 *font_data;
  102. stbtt_fontinfo font;
  103. struct pos_info pos[POS_HISTORY_SIZE];
  104. int pos_ptr;
  105. int baseline;
  106. double scale;
  107. };
  108. static int console_truetype_set_row(struct udevice *dev, uint row, int clr)
  109. {
  110. struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
  111. struct console_tt_priv *priv = dev_get_priv(dev);
  112. void *line;
  113. int pixels = priv->font_size * vid_priv->line_length;
  114. int i;
  115. line = vid_priv->fb + row * priv->font_size * vid_priv->line_length;
  116. switch (vid_priv->bpix) {
  117. #ifdef CONFIG_VIDEO_BPP8
  118. case VIDEO_BPP8: {
  119. uint8_t *dst = line;
  120. for (i = 0; i < pixels; i++)
  121. *dst++ = clr;
  122. break;
  123. }
  124. #endif
  125. #ifdef CONFIG_VIDEO_BPP16
  126. case VIDEO_BPP16: {
  127. uint16_t *dst = line;
  128. for (i = 0; i < pixels; i++)
  129. *dst++ = clr;
  130. break;
  131. }
  132. #endif
  133. #ifdef CONFIG_VIDEO_BPP32
  134. case VIDEO_BPP32: {
  135. uint32_t *dst = line;
  136. for (i = 0; i < pixels; i++)
  137. *dst++ = clr;
  138. break;
  139. }
  140. #endif
  141. default:
  142. return -ENOSYS;
  143. }
  144. return 0;
  145. }
  146. static int console_truetype_move_rows(struct udevice *dev, uint rowdst,
  147. uint rowsrc, uint count)
  148. {
  149. struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
  150. struct console_tt_priv *priv = dev_get_priv(dev);
  151. void *dst;
  152. void *src;
  153. int i, diff;
  154. dst = vid_priv->fb + rowdst * priv->font_size * vid_priv->line_length;
  155. src = vid_priv->fb + rowsrc * priv->font_size * vid_priv->line_length;
  156. memmove(dst, src, priv->font_size * vid_priv->line_length * count);
  157. /* Scroll up our position history */
  158. diff = (rowsrc - rowdst) * priv->font_size;
  159. for (i = 0; i < priv->pos_ptr; i++)
  160. priv->pos[i].ypos -= diff;
  161. return 0;
  162. }
  163. static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y,
  164. char ch)
  165. {
  166. struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
  167. struct udevice *vid = dev->parent;
  168. struct video_priv *vid_priv = dev_get_uclass_priv(vid);
  169. struct console_tt_priv *priv = dev_get_priv(dev);
  170. stbtt_fontinfo *font = &priv->font;
  171. int width, height, xoff, yoff;
  172. double xpos, x_shift;
  173. int lsb;
  174. int width_frac, linenum;
  175. struct pos_info *pos;
  176. u8 *bits, *data;
  177. int advance;
  178. void *line;
  179. int row;
  180. /* First get some basic metrics about this character */
  181. stbtt_GetCodepointHMetrics(font, ch, &advance, &lsb);
  182. /*
  183. * First out our current X position in fractional pixels. If we wrote
  184. * a character previously, using kerning to fine-tune the position of
  185. * this character */
  186. xpos = frac(VID_TO_PIXEL((double)x));
  187. if (vc_priv->last_ch) {
  188. xpos += priv->scale * stbtt_GetCodepointKernAdvance(font,
  189. vc_priv->last_ch, ch);
  190. }
  191. /*
  192. * Figure out where the cursor will move to after this character, and
  193. * abort if we are out of space on this line. Also calculate the
  194. * effective width of this character, which will be our return value:
  195. * it dictates how much the cursor will move forward on the line.
  196. */
  197. x_shift = xpos - (double)tt_floor(xpos);
  198. xpos += advance * priv->scale;
  199. width_frac = (int)VID_TO_POS(xpos);
  200. if (x + width_frac >= vc_priv->xsize_frac)
  201. return -EAGAIN;
  202. /* Write the current cursor position into history */
  203. if (priv->pos_ptr < POS_HISTORY_SIZE) {
  204. pos = &priv->pos[priv->pos_ptr];
  205. pos->xpos_frac = vc_priv->xcur_frac;
  206. pos->ypos = vc_priv->ycur;
  207. priv->pos_ptr++;
  208. }
  209. /*
  210. * Figure out how much past the start of a pixel we are, and pass this
  211. * information into the render, which will return a 8-bit-per-pixel
  212. * image of the character. For empty characters, like ' ', data will
  213. * return NULL;
  214. */
  215. data = stbtt_GetCodepointBitmapSubpixel(font, priv->scale, priv->scale,
  216. x_shift, 0, ch, &width, &height,
  217. &xoff, &yoff);
  218. if (!data)
  219. return width_frac;
  220. /* Figure out where to write the character in the frame buffer */
  221. bits = data;
  222. line = vid_priv->fb + y * vid_priv->line_length +
  223. VID_TO_PIXEL(x) * VNBYTES(vid_priv->bpix);
  224. linenum = priv->baseline + yoff;
  225. if (linenum > 0)
  226. line += linenum * vid_priv->line_length;
  227. /*
  228. * Write a row at a time, converting the 8bpp image into the colour
  229. * depth of the display. We only expect white-on-black or the reverse
  230. * so the code only handles this simple case.
  231. */
  232. for (row = 0; row < height; row++) {
  233. switch (vid_priv->bpix) {
  234. #ifdef CONFIG_VIDEO_BPP16
  235. case VIDEO_BPP16: {
  236. uint16_t *dst = (uint16_t *)line + xoff;
  237. int i;
  238. for (i = 0; i < width; i++) {
  239. int val = *bits;
  240. int out;
  241. if (vid_priv->colour_bg)
  242. val = 255 - val;
  243. out = val >> 3 |
  244. (val >> 2) << 5 |
  245. (val >> 3) << 11;
  246. if (vid_priv->colour_fg)
  247. *dst++ |= out;
  248. else
  249. *dst++ &= out;
  250. bits++;
  251. }
  252. break;
  253. }
  254. #endif
  255. default:
  256. free(data);
  257. return -ENOSYS;
  258. }
  259. line += vid_priv->line_length;
  260. }
  261. free(data);
  262. return width_frac;
  263. }
  264. /**
  265. * console_truetype_erase() - Erase a character
  266. *
  267. * This is used for backspace. We erase a square of the display within the
  268. * given bounds.
  269. *
  270. * @dev: Device to update
  271. * @xstart: X start position in pixels from the left
  272. * @ystart: Y start position in pixels from the top
  273. * @xend: X end position in pixels from the left
  274. * @yend: Y end position in pixels from the top
  275. * @clr: Value to write
  276. * @return 0 if OK, -ENOSYS if the display depth is not supported
  277. */
  278. static int console_truetype_erase(struct udevice *dev, int xstart, int ystart,
  279. int xend, int yend, int clr)
  280. {
  281. struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
  282. void *line;
  283. int pixels = xend - xstart;
  284. int row, i;
  285. line = vid_priv->fb + ystart * vid_priv->line_length;
  286. line += xstart * VNBYTES(vid_priv->bpix);
  287. for (row = ystart; row < yend; row++) {
  288. switch (vid_priv->bpix) {
  289. #ifdef CONFIG_VIDEO_BPP8
  290. case VIDEO_BPP8: {
  291. uint8_t *dst = line;
  292. for (i = 0; i < pixels; i++)
  293. *dst++ = clr;
  294. break;
  295. }
  296. #endif
  297. #ifdef CONFIG_VIDEO_BPP16
  298. case VIDEO_BPP16: {
  299. uint16_t *dst = line;
  300. for (i = 0; i < pixels; i++)
  301. *dst++ = clr;
  302. break;
  303. }
  304. #endif
  305. #ifdef CONFIG_VIDEO_BPP32
  306. case VIDEO_BPP32: {
  307. uint32_t *dst = line;
  308. for (i = 0; i < pixels; i++)
  309. *dst++ = clr;
  310. break;
  311. }
  312. #endif
  313. default:
  314. return -ENOSYS;
  315. }
  316. line += vid_priv->line_length;
  317. }
  318. return 0;
  319. }
  320. /**
  321. * console_truetype_backspace() - Handle a backspace operation
  322. *
  323. * This clears the previous character so that the console looks as if it had
  324. * not been entered.
  325. *
  326. * @dev: Device to update
  327. * @return 0 if OK, -ENOSYS if not supported
  328. */
  329. static int console_truetype_backspace(struct udevice *dev)
  330. {
  331. struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
  332. struct console_tt_priv *priv = dev_get_priv(dev);
  333. struct udevice *vid_dev = dev->parent;
  334. struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev);
  335. struct pos_info *pos;
  336. int xend;
  337. /*
  338. * This indicates a very strange error higher in the stack. The caller
  339. * has sent out n character and n + 1 backspaces.
  340. */
  341. if (!priv->pos_ptr)
  342. return -ENOSYS;
  343. /* Pop the last cursor position off the stack */
  344. pos = &priv->pos[--priv->pos_ptr];
  345. /*
  346. * Figure out the end position for clearing. Normlly it is the current
  347. * cursor position, but if we are clearing a character on the previous
  348. * line, we clear from the end of the line.
  349. */
  350. if (pos->ypos == vc_priv->ycur)
  351. xend = VID_TO_PIXEL(vc_priv->xcur_frac);
  352. else
  353. xend = vid_priv->xsize;
  354. console_truetype_erase(dev, VID_TO_PIXEL(pos->xpos_frac), pos->ypos,
  355. xend, pos->ypos + vc_priv->y_charsize,
  356. vid_priv->colour_bg);
  357. /* Move the cursor back to where it was when we pushed this record */
  358. vc_priv->xcur_frac = pos->xpos_frac;
  359. vc_priv->ycur = pos->ypos;
  360. return 0;
  361. }
  362. static int console_truetype_entry_start(struct udevice *dev)
  363. {
  364. struct console_tt_priv *priv = dev_get_priv(dev);
  365. /* A new input line has start, so clear our history */
  366. priv->pos_ptr = 0;
  367. return 0;
  368. }
  369. /*
  370. * Provides a list of fonts which can be obtained at run-time in U-Boot. These
  371. * are compiled in by the Makefile.
  372. *
  373. * At present there is no mechanism to select a particular font - the first
  374. * one found is the one that is used. But the build system and the code here
  375. * supports multiple fonts, which may be useful for certain firmware screens.
  376. */
  377. struct font_info {
  378. char *name;
  379. u8 *begin;
  380. u8 *end;
  381. };
  382. #define FONT_DECL(_name) \
  383. extern u8 __ttf_ ## _name ## _begin[]; \
  384. extern u8 __ttf_ ## _name ## _end[];
  385. #define FONT_ENTRY(_name) { \
  386. .name = #_name, \
  387. .begin = __ttf_ ## _name ## _begin, \
  388. .end = __ttf_ ## _name ## _end, \
  389. }
  390. FONT_DECL(nimbus_sans_l_regular);
  391. FONT_DECL(ankacoder_c75_r);
  392. FONT_DECL(rufscript010);
  393. FONT_DECL(cantoraone_regular);
  394. static struct font_info font_table[] = {
  395. #ifdef CONFIG_CONSOLE_TRUETYPE_NIMBUS
  396. FONT_ENTRY(nimbus_sans_l_regular),
  397. #endif
  398. #ifdef CONFIG_CONSOLE_TRUETYPE_ANKACODER
  399. FONT_ENTRY(ankacoder_c75_r),
  400. #endif
  401. #ifdef CONFIG_CONSOLE_TRUETYPE_RUFSCRIPT
  402. FONT_ENTRY(rufscript010),
  403. #endif
  404. #ifdef CONFIG_CONSOLE_TRUETYPE_CANTORAONE
  405. FONT_ENTRY(cantoraone_regular),
  406. #endif
  407. {} /* sentinel */
  408. };
  409. #define FONT_BEGIN(name) __ttf_ ## name ## _begin
  410. #define FONT_END(name) __ttf_ ## name ## _end
  411. #define FONT_IS_VALID(name) (abs(FONT_END(name) - FONT_BEGIN) > 4)
  412. /**
  413. * console_truetype_find_font() - Find a suitable font
  414. *
  415. * This searched for the first available font.
  416. *
  417. * @return pointer to the font, or NULL if none is found
  418. */
  419. static u8 *console_truetype_find_font(void)
  420. {
  421. struct font_info *tab;
  422. for (tab = font_table; tab->begin; tab++) {
  423. if (abs(tab->begin - tab->end) > 4) {
  424. debug("%s: Font '%s', at %p, size %lx\n", __func__,
  425. tab->name, tab->begin,
  426. (ulong)(tab->end - tab->begin));
  427. return tab->begin;
  428. }
  429. }
  430. return NULL;
  431. }
  432. static int console_truetype_probe(struct udevice *dev)
  433. {
  434. struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
  435. struct console_tt_priv *priv = dev_get_priv(dev);
  436. struct udevice *vid_dev = dev->parent;
  437. struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev);
  438. stbtt_fontinfo *font = &priv->font;
  439. int ascent;
  440. debug("%s: start\n", __func__);
  441. if (vid_priv->font_size)
  442. priv->font_size = vid_priv->font_size;
  443. else
  444. priv->font_size = CONFIG_CONSOLE_TRUETYPE_SIZE;
  445. priv->font_data = console_truetype_find_font();
  446. if (!priv->font_data) {
  447. debug("%s: Could not find any fonts\n", __func__);
  448. return -EBFONT;
  449. }
  450. vc_priv->x_charsize = priv->font_size;
  451. vc_priv->y_charsize = priv->font_size;
  452. vc_priv->xstart_frac = VID_TO_POS(2);
  453. vc_priv->cols = vid_priv->xsize / priv->font_size;
  454. vc_priv->rows = vid_priv->ysize / priv->font_size;
  455. vc_priv->tab_width_frac = VID_TO_POS(priv->font_size) * 8 / 2;
  456. if (!stbtt_InitFont(font, priv->font_data, 0)) {
  457. debug("%s: Font init failed\n", __func__);
  458. return -EPERM;
  459. }
  460. /* Pre-calculate some things we will need regularly */
  461. priv->scale = stbtt_ScaleForPixelHeight(font, priv->font_size);
  462. stbtt_GetFontVMetrics(font, &ascent, 0, 0);
  463. priv->baseline = (int)(ascent * priv->scale);
  464. debug("%s: ready\n", __func__);
  465. return 0;
  466. }
  467. struct vidconsole_ops console_truetype_ops = {
  468. .putc_xy = console_truetype_putc_xy,
  469. .move_rows = console_truetype_move_rows,
  470. .set_row = console_truetype_set_row,
  471. .backspace = console_truetype_backspace,
  472. .entry_start = console_truetype_entry_start,
  473. };
  474. U_BOOT_DRIVER(vidconsole_truetype) = {
  475. .name = "vidconsole_tt",
  476. .id = UCLASS_VIDEO_CONSOLE,
  477. .ops = &console_truetype_ops,
  478. .probe = console_truetype_probe,
  479. .priv_auto_alloc_size = sizeof(struct console_tt_priv),
  480. };