nxcon_font.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. /****************************************************************************
  2. * nuttx/graphics/nxconsole/nxcon_font.c
  3. *
  4. * Copyright (C) 2012 Gregory Nutt. All rights reserved.
  5. * Author: Gregory Nutt <gnutt@nuttx.org>
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in
  15. * the documentation and/or other materials provided with the
  16. * distribution.
  17. * 3. Neither the name NuttX nor the names of its contributors may be
  18. * used to endorse or promote products derived from this software
  19. * without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  24. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  25. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  26. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  27. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  28. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  29. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  31. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  32. * POSSIBILITY OF SUCH DAMAGE.
  33. *
  34. ****************************************************************************/
  35. /****************************************************************************
  36. * Included Files
  37. ****************************************************************************/
  38. #include <nuttx/config.h>
  39. #include <string.h>
  40. #include <assert.h>
  41. #include <errno.h>
  42. #include <debug.h>
  43. #include <nuttx/kmalloc.h>
  44. #include "nxcon_internal.h"
  45. /****************************************************************************
  46. * Definitions
  47. ****************************************************************************/
  48. /* Select renderer -- Some additional logic would be required to support
  49. * pixel depths that are not directly addressable (1,2,4, and 24).
  50. */
  51. #if CONFIG_NXCONSOLE_BPP == 1
  52. # define RENDERER nxf_convert_1bpp
  53. #elif CONFIG_NXCONSOLE_BPP == 2
  54. # define RENDERER nxf_convert_2bpp
  55. #elif CONFIG_NXCONSOLE_BPP == 4
  56. # define RENDERER nxf_convert_4bpp
  57. #elif CONFIG_NXCONSOLE_BPP == 8
  58. # define RENDERER nxf_convert_8bpp
  59. #elif CONFIG_NXCONSOLE_BPP == 16
  60. # define RENDERER nxf_convert_16bpp
  61. #elif CONFIG_NXCONSOLE_BPP == 24
  62. # define RENDERER nxf_convert_24bpp
  63. #elif CONFIG_NXCONSOLE_BPP == 32
  64. # define RENDERER nxf_convert_32bpp
  65. #else
  66. # error "Unsupported CONFIG_NXCONSOLE_BPP"
  67. #endif
  68. /****************************************************************************
  69. * Private Types
  70. ****************************************************************************/
  71. /****************************************************************************
  72. * Private Function Prototypes
  73. ****************************************************************************/
  74. /****************************************************************************
  75. * Private Data
  76. ****************************************************************************/
  77. /****************************************************************************
  78. * Public Data
  79. ****************************************************************************/
  80. /****************************************************************************
  81. * Private Functions
  82. ****************************************************************************/
  83. /****************************************************************************
  84. * Name: nxcon_freeglyph
  85. ****************************************************************************/
  86. static void nxcon_freeglyph(FAR struct nxcon_glyph_s *glyph)
  87. {
  88. if (glyph->bitmap)
  89. {
  90. kfree(glyph->bitmap);
  91. }
  92. memset(glyph, 0, sizeof(struct nxcon_glyph_s));
  93. }
  94. /****************************************************************************
  95. * Name: nxcon_allocglyph
  96. ****************************************************************************/
  97. static inline FAR struct nxcon_glyph_s *
  98. nxcon_allocglyph(FAR struct nxcon_state_s *priv)
  99. {
  100. FAR struct nxcon_glyph_s *glyph = NULL;
  101. FAR struct nxcon_glyph_s *luglyph = NULL;
  102. uint8_t luusecnt;
  103. int i;
  104. /* Search through the glyph cache looking for an unused glyph. Also, keep
  105. * track of the least used glyph as well. We need that if we have to replace
  106. * a glyph in the cache.
  107. */
  108. for (i = 0; i < priv->maxglyphs; i++)
  109. {
  110. /* Is this glyph in use? */
  111. glyph = &priv->glyph[i];
  112. if (!glyph->usecnt)
  113. {
  114. /* No.. return this glyph with a use count of one */
  115. glyph->usecnt = 1;
  116. return glyph;
  117. }
  118. /* Yes.. check for the least recently used */
  119. if (!luglyph || glyph->usecnt < luglyph->usecnt)
  120. {
  121. luglyph = glyph;
  122. }
  123. }
  124. /* If we get here, the glyph cache is full. We replace the least used
  125. * glyph with the one we need now. (luglyph can't be NULL).
  126. */
  127. luusecnt = luglyph->usecnt;
  128. nxcon_freeglyph(luglyph);
  129. /* But lets decrement all of the usecnts so that the new one one be so
  130. * far behind in the counts as the older ones.
  131. */
  132. if (luusecnt > 1)
  133. {
  134. uint8_t decr = luusecnt - 1;
  135. for (i = 0; i < priv->maxglyphs; i++)
  136. {
  137. /* Is this glyph in use? */
  138. glyph = &priv->glyph[i];
  139. if (glyph->usecnt > decr)
  140. {
  141. glyph->usecnt -= decr;
  142. }
  143. }
  144. }
  145. /* Then return the least used glyph */
  146. luglyph->usecnt = 1;
  147. return luglyph;
  148. }
  149. /****************************************************************************
  150. * Name: nxcon_findglyph
  151. ****************************************************************************/
  152. static FAR struct nxcon_glyph_s *
  153. nxcon_findglyph(FAR struct nxcon_state_s *priv, uint8_t ch)
  154. {
  155. int i;
  156. /* First, try to find the glyph in the cache of pre-rendered glyphs */
  157. for (i = 0; i < priv->maxglyphs; i++)
  158. {
  159. FAR struct nxcon_glyph_s *glyph = &priv->glyph[i];
  160. if (glyph->usecnt > 0 && glyph->code == ch)
  161. {
  162. /* Increment the use count (unless it is already at the max) */
  163. if (glyph->usecnt < MAX_USECNT)
  164. {
  165. glyph->usecnt++;
  166. }
  167. /* And return the glyph that we found */
  168. return glyph;
  169. }
  170. }
  171. return NULL;
  172. }
  173. /****************************************************************************
  174. * Name: nxcon_renderglyph
  175. ****************************************************************************/
  176. static inline FAR struct nxcon_glyph_s *
  177. nxcon_renderglyph(FAR struct nxcon_state_s *priv,
  178. FAR const struct nx_fontbitmap_s *fbm, uint8_t ch)
  179. {
  180. FAR struct nxcon_glyph_s *glyph = NULL;
  181. FAR nxgl_mxpixel_t *ptr;
  182. #if CONFIG_NXCONSOLE_BPP < 8
  183. nxgl_mxpixel_t pixel;
  184. #endif
  185. int bmsize;
  186. int row;
  187. int col;
  188. int ret;
  189. /* Allocate the glyph (always succeeds) */
  190. glyph = nxcon_allocglyph(priv);
  191. glyph->code = ch;
  192. /* Get the dimensions of the glyph */
  193. glyph->width = fbm->metric.width + fbm->metric.xoffset;
  194. glyph->height = fbm->metric.height + fbm->metric.yoffset;
  195. /* Get the physical width of the glyph in bytes */
  196. glyph->stride = (glyph->width * CONFIG_NXCONSOLE_BPP + 7) / 8;
  197. /* Allocate memory to hold the glyph with its offsets */
  198. bmsize = glyph->stride * glyph->height;
  199. glyph->bitmap = (FAR uint8_t *)kmalloc(bmsize);
  200. if (glyph->bitmap)
  201. {
  202. /* Initialize the glyph memory to the background color using the
  203. * hard-coded bits-per-pixel (BPP).
  204. *
  205. * TODO: The rest of NX is configured to support multiple devices
  206. * with differing BPP. They logic should be extended to support
  207. * differing BPP's as well.
  208. */
  209. #if CONFIG_NXCONSOLE_BPP < 8
  210. pixel = priv->wcolor[0];
  211. # if CONFIG_NXCONSOLE_BPP == 1
  212. /* Pack 1-bit pixels into a 2-bits */
  213. pixel &= 0x01;
  214. pixel = (pixel) << 1 | pixel;
  215. # endif
  216. # if CONFIG_NXCONSOLE_BPP < 4
  217. /* Pack 2-bit pixels into a nibble */
  218. pixel &= 0x03;
  219. pixel = (pixel) << 2 | pixel;
  220. # endif
  221. /* Pack 4-bit nibbles into a byte */
  222. pixel &= 0x0f;
  223. pixel = (pixel) << 4 | pixel;
  224. ptr = (FAR nxgl_mxpixel_t *)glyph->bitmap;
  225. for (row = 0; row < glyph->height; row++)
  226. {
  227. for (col = 0; col < glyph->stride; col++)
  228. {
  229. /* Transfer the packed bytes into the buffer */
  230. *ptr++ = pixel;
  231. }
  232. }
  233. #elif CONFIG_NXCONSOLE_BPP == 24
  234. # error "Additional logic is needed here for 24bpp support"
  235. #else /* CONFIG_NXCONSOLE_BPP = {8,16,32} */
  236. ptr = (FAR nxgl_mxpixel_t *)glyph->bitmap;
  237. for (row = 0; row < glyph->height; row++)
  238. {
  239. /* Just copy the color value into the glyph memory */
  240. for (col = 0; col < glyph->width; col++)
  241. {
  242. *ptr++ = priv->wndo.wcolor[0];
  243. }
  244. }
  245. #endif
  246. /* Then render the glyph into the allocated memory */
  247. ret = RENDERER((FAR nxgl_mxpixel_t*)glyph->bitmap,
  248. glyph->height, glyph->width, glyph->stride,
  249. fbm, priv->wndo.fcolor[0]);
  250. if (ret < 0)
  251. {
  252. /* Actually, the RENDERER never returns a failure */
  253. gdbg("nxcon_renderglyph: RENDERER failed\n");
  254. nxcon_freeglyph(glyph);
  255. glyph = NULL;
  256. }
  257. }
  258. return glyph;
  259. }
  260. /****************************************************************************
  261. * Name: nxcon_fontsize
  262. ****************************************************************************/
  263. static int nxcon_fontsize(NXHANDLE hfont, uint8_t ch, FAR struct nxgl_size_s *size)
  264. {
  265. FAR const struct nx_fontbitmap_s *fbm;
  266. /* No, it is not cached... Does the code map to a font? */
  267. fbm = nxf_getbitmap(hfont, ch);
  268. if (fbm)
  269. {
  270. /* Yes.. return the font size */
  271. size->w = fbm->metric.width + fbm->metric.xoffset;
  272. size->h = fbm->metric.height + fbm->metric.yoffset;
  273. return OK;
  274. }
  275. return ERROR;
  276. }
  277. /****************************************************************************
  278. * Name: nxcon_getglyph
  279. ****************************************************************************/
  280. static FAR struct nxcon_glyph_s *
  281. nxcon_getglyph(NXHANDLE hfont, FAR struct nxcon_state_s *priv, uint8_t ch)
  282. {
  283. FAR struct nxcon_glyph_s *glyph;
  284. FAR const struct nx_fontbitmap_s *fbm;
  285. /* First, try to find the glyph in the cache of pre-rendered glyphs */
  286. glyph = nxcon_findglyph(priv, ch);
  287. if (glyph)
  288. {
  289. /* We found it in the cache .. return the cached glyph */
  290. return glyph;
  291. }
  292. /* No, it is not cached... Does the code map to a font? */
  293. fbm = nxf_getbitmap(hfont, ch);
  294. if (fbm)
  295. {
  296. /* Yes.. render the glyph */
  297. glyph = nxcon_renderglyph(priv, fbm, ch);
  298. }
  299. return glyph;
  300. }
  301. /****************************************************************************
  302. * Public Functions
  303. ****************************************************************************/
  304. /****************************************************************************
  305. * Name: nxcon_addchar
  306. *
  307. * Description:
  308. * This is part of the nxcon_putc logic. It creates and positions a
  309. * the character and renders (or re-uses) a glyph for font.
  310. *
  311. ****************************************************************************/
  312. FAR const struct nxcon_bitmap_s *
  313. nxcon_addchar(NXHANDLE hfont, FAR struct nxcon_state_s *priv, uint8_t ch)
  314. {
  315. FAR struct nxcon_bitmap_s *bm = NULL;
  316. FAR struct nxcon_glyph_s *glyph;
  317. /* Is there space for another character on the display? */
  318. if (priv->nchars < priv->maxchars)
  319. {
  320. /* Yes, setup the bitmap information */
  321. bm = &priv->bm[priv->nchars];
  322. bm->code = ch;
  323. bm->flags = 0;
  324. bm->pos.x = priv->fpos.x;
  325. bm->pos.y = priv->fpos.y;
  326. /* Find (or create) the matching glyph */
  327. glyph = nxcon_getglyph(hfont, priv, ch);
  328. if (!glyph)
  329. {
  330. /* No, there is no font for this code. Just mark this as a space. */
  331. bm->flags |= BMFLAGS_NOGLYPH;
  332. /* Set up the next character position */
  333. priv->fpos.x += priv->spwidth;
  334. }
  335. else
  336. {
  337. /* Set up the next character position */
  338. priv->fpos.x += glyph->width;
  339. }
  340. /* Success.. increment nchars to retain this character */
  341. priv->nchars++;
  342. }
  343. return bm;
  344. }
  345. /****************************************************************************
  346. * Name: nxcon_hidechar
  347. *
  348. * Description:
  349. * Erase a character from the window.
  350. *
  351. ****************************************************************************/
  352. int nxcon_hidechar(FAR struct nxcon_state_s *priv,
  353. FAR const struct nxcon_bitmap_s *bm)
  354. {
  355. struct nxgl_rect_s bounds;
  356. struct nxgl_size_s fsize;
  357. int ret;
  358. /* Get the size of the font glyph. If nxcon_fontsize, then the
  359. * character will have been rendered as a space, and no display
  360. * modification is required (not an error).
  361. */
  362. ret = nxcon_fontsize(priv->font, bm->code, &fsize);
  363. if (ret < 0)
  364. {
  365. /* It was rendered as a space. */
  366. return OK;
  367. }
  368. /* Construct a bounding box for the glyph */
  369. bounds.pt1.x = bm->pos.x;
  370. bounds.pt1.y = bm->pos.y;
  371. bounds.pt2.x = bm->pos.x + fsize.w - 1;
  372. bounds.pt2.y = bm->pos.y + fsize.h - 1;
  373. /* Fill the bitmap region with the background color, erasing the
  374. * character from the display. NOTE: This region might actually
  375. * be obscured... NX will handle that case.
  376. */
  377. return priv->ops->fill(priv, &bounds, priv->wndo.wcolor);
  378. }
  379. /****************************************************************************
  380. * Name: nxcon_backspace
  381. *
  382. * Description:
  383. * Remove the last character from the window.
  384. *
  385. ****************************************************************************/
  386. int nxcon_backspace(FAR struct nxcon_state_s *priv)
  387. {
  388. FAR struct nxcon_bitmap_s *bm;
  389. int ndx;
  390. int ret = -ENOENT;
  391. /* Is there a character on the display? */
  392. if (priv->nchars > 0)
  393. {
  394. /* Yes.. Get the index to the last bitmap on the display */
  395. ndx = priv->nchars - 1;
  396. bm = &priv->bm[ndx];
  397. /* Erase the character from the display */
  398. ret = nxcon_hidechar(priv, bm);
  399. /* The current position to the location where the last character was */
  400. priv->fpos.x = bm->pos.x;
  401. priv->fpos.y = bm->pos.y;
  402. /* Decrement nchars to discard this character */
  403. priv->nchars = ndx;
  404. }
  405. return ret;
  406. }
  407. /****************************************************************************
  408. * Name: nxcon_home
  409. *
  410. * Description:
  411. * Set the next character position to the top-left corner of the display.
  412. *
  413. ****************************************************************************/
  414. void nxcon_home(FAR struct nxcon_state_s *priv)
  415. {
  416. /* The first character is one space from the left */
  417. priv->fpos.x = priv->spwidth;
  418. /* And CONFIG_NXCONSOLE_LINESEPARATION lines from the top */
  419. priv->fpos.y = CONFIG_NXCONSOLE_LINESEPARATION;
  420. }
  421. /****************************************************************************
  422. * Name: nxcon_newline
  423. *
  424. * Description:
  425. * Set the next character position to the beginning of the next line.
  426. *
  427. ****************************************************************************/
  428. void nxcon_newline(FAR struct nxcon_state_s *priv)
  429. {
  430. /* Carriage return: The first character is one space from the left */
  431. priv->fpos.x = priv->spwidth;
  432. /* Linefeed: Down the max font height + CONFIG_NXCONSOLE_LINESEPARATION */
  433. priv->fpos.y += (priv->fheight + CONFIG_NXCONSOLE_LINESEPARATION);
  434. }
  435. /****************************************************************************
  436. * Name: nxcon_fillchar
  437. *
  438. * Description:
  439. * This implements the character display. It is part of the nxcon_putc
  440. * operation but may also be used when redrawing an existing display.
  441. *
  442. ****************************************************************************/
  443. void nxcon_fillchar(FAR struct nxcon_state_s *priv,
  444. FAR const struct nxgl_rect_s *rect,
  445. FAR const struct nxcon_bitmap_s *bm)
  446. {
  447. FAR struct nxcon_glyph_s *glyph;
  448. struct nxgl_rect_s bounds;
  449. struct nxgl_rect_s intersection;
  450. struct nxgl_size_s fsize;
  451. int ret;
  452. /* Handle the special case of spaces which have no glyph bitmap */
  453. if (BM_ISSPACE(bm))
  454. {
  455. return;
  456. }
  457. /* Get the size of the font glyph (which may not have been created yet) */
  458. ret = nxcon_fontsize(priv->font, bm->code, &fsize);
  459. if (ret < 0)
  460. {
  461. /* This would mean that there is no bitmap for the character code and
  462. * that the font would be rendered as a space. But this case should
  463. * never happen here because the BM_ISSPACE() should have already
  464. * found all such cases.
  465. */
  466. return;
  467. }
  468. /* Construct a bounding box for the glyph */
  469. bounds.pt1.x = bm->pos.x;
  470. bounds.pt1.y = bm->pos.y;
  471. bounds.pt2.x = bm->pos.x + fsize.w - 1;
  472. bounds.pt2.y = bm->pos.y + fsize.h - 1;
  473. /* Should this also be clipped to a region in the window? */
  474. if (rect)
  475. {
  476. /* Get the intersection of the redraw region and the character bitmap */
  477. nxgl_rectintersect(&intersection, rect, &bounds);
  478. }
  479. else
  480. {
  481. /* The intersection is the whole glyph */
  482. nxgl_rectcopy(&intersection, &bounds);
  483. }
  484. /* Check for empty intersections */
  485. if (!nxgl_nullrect(&intersection))
  486. {
  487. FAR const void *src;
  488. /* Find (or create) the glyph that goes with this font */
  489. glyph = nxcon_getglyph(priv->font, priv, bm->code);
  490. if (!glyph)
  491. {
  492. /* Shouldn't happen */
  493. return;
  494. }
  495. /* Blit the font bitmap into the window */
  496. src = (FAR const void *)glyph->bitmap;
  497. ret = priv->ops->bitmap(priv, &intersection, &src,
  498. &bm->pos, (unsigned int)glyph->stride);
  499. DEBUGASSERT(ret >= 0);
  500. }
  501. }