console_truetype.c 15 KB

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