25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

font.c 16 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. /*
  2. * libcucul Canvas for ultrafast compositing of Unicode letters
  3. * Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org>
  4. * All Rights Reserved
  5. *
  6. * $Id$
  7. *
  8. * This library is free software. It comes without any warranty, to
  9. * the extent permitted by applicable law. You can redistribute it
  10. * and/or modify it under the terms of the Do What The Fuck You Want
  11. * To Public License, Version 2, as published by Sam Hocevar. See
  12. * http://sam.zoy.org/wtfpl/COPYING for more details.
  13. */
  14. /*
  15. * This file contains font handling functions.
  16. */
  17. #include "config.h"
  18. #if !defined(__KERNEL__)
  19. # if defined(HAVE_ENDIAN_H)
  20. # include <endian.h>
  21. # endif
  22. # include <stdio.h>
  23. # include <stdlib.h>
  24. # include <string.h>
  25. #endif
  26. #include "cucul.h"
  27. #include "cucul_internals.h"
  28. /* Internal fonts */
  29. #include "mono9.data"
  30. #include "monobold12.data"
  31. /* Helper structures for font loading */
  32. #if !defined(_DOXYGEN_SKIP_ME)
  33. struct font_header
  34. {
  35. uint32_t control_size, data_size;
  36. uint16_t version, blocks;
  37. uint32_t glyphs;
  38. uint16_t bpp, width, height, maxwidth, maxheight, flags;
  39. };
  40. struct block_info
  41. {
  42. uint32_t start, stop, index;
  43. };
  44. struct glyph_info
  45. {
  46. uint16_t width, height;
  47. uint32_t data_offset;
  48. };
  49. struct cucul_font
  50. {
  51. struct font_header header;
  52. struct block_info *block_list;
  53. unsigned long int *user_block_list;
  54. struct glyph_info *glyph_list;
  55. uint8_t *font_data;
  56. uint8_t *private;
  57. };
  58. #endif
  59. #define DECLARE_UNPACKGLYPH(bpp) \
  60. static inline void \
  61. unpack_glyph ## bpp(uint8_t *glyph, uint8_t *packed_data, \
  62. unsigned int n) \
  63. { \
  64. unsigned int i; \
  65. \
  66. for(i = 0; i < n; i++) \
  67. { \
  68. uint8_t pixel = packed_data[i / (8 / bpp)]; \
  69. pixel >>= bpp * ((8 / bpp) - 1 - (i % (8 / bpp))); \
  70. pixel %= (1 << bpp); \
  71. pixel *= 0xff / ((1 << bpp) - 1); \
  72. *glyph++ = pixel; \
  73. } \
  74. }
  75. DECLARE_UNPACKGLYPH(4)
  76. DECLARE_UNPACKGLYPH(2)
  77. DECLARE_UNPACKGLYPH(1)
  78. /** \brief Load a font from memory for future use.
  79. *
  80. * This function loads a font and returns a handle to its internal
  81. * structure. The handle can then be used with cucul_render_canvas()
  82. * for bitmap output.
  83. *
  84. * Internal fonts can also be loaded: if \c size is set to 0, \c data must
  85. * be a string containing the internal font name.
  86. *
  87. * If \c size is non-zero, the \c size bytes of memory at address \c data
  88. * are loaded as a font. This memory are must not be freed by the calling
  89. * program until the font handle has been freed with cucul_free_font().
  90. *
  91. * If an error occurs, NULL is returned and \b errno is set accordingly:
  92. * - \c ENOENT Requested built-in font does not exist.
  93. * - \c EINVAL Invalid font data in memory area.
  94. * - \c ENOMEM Not enough memory to allocate font structure.
  95. *
  96. * \param data The memory area containing the font or its name.
  97. * \param size The size of the memory area, or 0 if the font name is given.
  98. * \return A font handle or NULL in case of error.
  99. */
  100. cucul_font_t *cucul_load_font(void const *data, unsigned int size)
  101. {
  102. cucul_font_t *f;
  103. unsigned int i;
  104. if(size == 0)
  105. {
  106. if(!strcasecmp(data, "Monospace 9"))
  107. return cucul_load_font((char *)&mono9_data, mono9_size);
  108. if(!strcasecmp(data, "Monospace Bold 12"))
  109. return cucul_load_font((char *)&monobold12_data, monobold12_size);
  110. seterrno(ENOENT);
  111. return NULL;
  112. }
  113. if(size < sizeof(struct font_header))
  114. {
  115. debug("font error: data size %i < header size %i",
  116. size, (int)sizeof(struct font_header));
  117. seterrno(EINVAL);
  118. return NULL;
  119. }
  120. f = malloc(sizeof(cucul_font_t));
  121. if(!f)
  122. {
  123. seterrno(ENOMEM);
  124. return NULL;
  125. }
  126. f->private = (void *)(uintptr_t)data;
  127. memcpy(&f->header, f->private + 4, sizeof(struct font_header));
  128. f->header.control_size = hton32(f->header.control_size);
  129. f->header.data_size = hton32(f->header.data_size);
  130. f->header.version = hton16(f->header.version);
  131. f->header.blocks = hton16(f->header.blocks);
  132. f->header.glyphs = hton32(f->header.glyphs);
  133. f->header.bpp = hton16(f->header.bpp);
  134. f->header.width = hton16(f->header.width);
  135. f->header.height = hton16(f->header.height);
  136. f->header.maxwidth = hton16(f->header.maxwidth);
  137. f->header.maxheight = hton16(f->header.maxheight);
  138. f->header.flags = hton16(f->header.flags);
  139. if(size != 4 + f->header.control_size + f->header.data_size
  140. || (f->header.bpp != 8 && f->header.bpp != 4 &&
  141. f->header.bpp != 2 && f->header.bpp != 1)
  142. || (f->header.flags & 1) == 0)
  143. {
  144. #if defined DEBUG
  145. if(size != 4 + f->header.control_size + f->header.data_size)
  146. debug("font error: data size %i < expected size %i",
  147. size, 4 + f->header.control_size + f->header.data_size);
  148. else if(f->header.bpp != 8 && f->header.bpp != 4 &&
  149. f->header.bpp != 2 && f->header.bpp != 1)
  150. debug("font error: invalid bpp %i", f->header.bpp);
  151. else if((f->header.flags & 1) == 0)
  152. debug("font error: invalid flags %.04x", f->header.flags);
  153. #endif
  154. free(f);
  155. seterrno(EINVAL);
  156. return NULL;
  157. }
  158. f->block_list = malloc(f->header.blocks * sizeof(struct block_info));
  159. if(!f->block_list)
  160. {
  161. free(f);
  162. seterrno(ENOMEM);
  163. return NULL;
  164. }
  165. f->user_block_list = malloc((f->header.blocks + 1)
  166. * 2 * sizeof(unsigned long int));
  167. if(!f->user_block_list)
  168. {
  169. free(f->block_list);
  170. free(f);
  171. seterrno(ENOMEM);
  172. return NULL;
  173. }
  174. memcpy(f->block_list,
  175. f->private + 4 + sizeof(struct font_header),
  176. f->header.blocks * sizeof(struct block_info));
  177. for(i = 0; i < f->header.blocks; i++)
  178. {
  179. f->block_list[i].start = hton32(f->block_list[i].start);
  180. f->block_list[i].stop = hton32(f->block_list[i].stop);
  181. f->block_list[i].index = hton32(f->block_list[i].index);
  182. if(f->block_list[i].start > f->block_list[i].stop
  183. || (i > 0 && f->block_list[i].start < f->block_list[i - 1].stop)
  184. || f->block_list[i].index >= f->header.glyphs)
  185. {
  186. #if defined DEBUG
  187. if(f->block_list[i].start > f->block_list[i].stop)
  188. debug("font error: block %i has start %i > stop %i",
  189. i, f->block_list[i].start, f->block_list[i].stop);
  190. else if(i > 0 && f->block_list[i].start < f->block_list[i - 1].stop)
  191. debug("font error: block %i has start %i < previous stop %i",
  192. f->block_list[i].start, f->block_list[i - 1].stop);
  193. else if(f->block_list[i].index >= f->header.glyphs)
  194. debug("font error: block %i has index >= glyph count %i",
  195. f->block_list[i].index, f->header.glyphs);
  196. #endif
  197. free(f->user_block_list);
  198. free(f->block_list);
  199. free(f);
  200. seterrno(EINVAL);
  201. return NULL;
  202. }
  203. f->user_block_list[i * 2] = f->block_list[i].start;
  204. f->user_block_list[i * 2 + 1] = f->block_list[i].stop;
  205. }
  206. f->user_block_list[i * 2] = 0;
  207. f->user_block_list[i * 2 + 1] = 0;
  208. f->glyph_list = malloc(f->header.glyphs * sizeof(struct glyph_info));
  209. if(!f->glyph_list)
  210. {
  211. free(f->user_block_list);
  212. free(f->block_list);
  213. free(f);
  214. seterrno(ENOMEM);
  215. return NULL;
  216. }
  217. memcpy(f->glyph_list,
  218. f->private + 4 + sizeof(struct font_header)
  219. + f->header.blocks * sizeof(struct block_info),
  220. f->header.glyphs * sizeof(struct glyph_info));
  221. for(i = 0; i < f->header.glyphs; i++)
  222. {
  223. f->glyph_list[i].width = hton16(f->glyph_list[i].width);
  224. f->glyph_list[i].height = hton16(f->glyph_list[i].height);
  225. f->glyph_list[i].data_offset = hton32(f->glyph_list[i].data_offset);
  226. if(f->glyph_list[i].data_offset >= f->header.data_size
  227. || f->glyph_list[i].data_offset
  228. + (f->glyph_list[i].width * f->glyph_list[i].height *
  229. f->header.bpp + 7) / 8 > f->header.data_size
  230. || f->glyph_list[i].width > f->header.maxwidth
  231. || f->glyph_list[i].height > f->header.maxheight)
  232. {
  233. #if defined DEBUG
  234. if(f->glyph_list[i].data_offset >= f->header.data_size)
  235. debug("font error: glyph %i has data start %i > "
  236. "data end %i",
  237. f->glyph_list[i].data_offset, f->header.data_size);
  238. else if(f->glyph_list[i].data_offset
  239. + (f->glyph_list[i].width * f->glyph_list[i].height *
  240. f->header.bpp + 7) / 8 > f->header.data_size)
  241. debug("font error: glyph %i has data end %i > "
  242. "data end %i", f->glyph_list[i].data_offset
  243. + (f->glyph_list[i].width * f->glyph_list[i].height *
  244. f->header.bpp + 7) / 8, f->header.data_size);
  245. else if(f->glyph_list[i].width > f->header.maxwidth)
  246. debug("font error: glyph %i has width %i > max width %i",
  247. f->glyph_list[i].width, f->header.maxwidth);
  248. else if(f->glyph_list[i].height > f->header.maxheight)
  249. debug("font error: glyph %i has height %i > max height %i",
  250. f->glyph_list[i].height, f->header.maxheight);
  251. #endif
  252. free(f->glyph_list);
  253. free(f->user_block_list);
  254. free(f->block_list);
  255. free(f);
  256. seterrno(EINVAL);
  257. return NULL;
  258. }
  259. }
  260. f->font_data = f->private + 4 + f->header.control_size;
  261. return f;
  262. }
  263. /** \brief Get available builtin fonts
  264. *
  265. * Return a list of available builtin fonts. The list is a NULL-terminated
  266. * array of strings.
  267. *
  268. * This function never fails.
  269. *
  270. * \return An array of strings.
  271. */
  272. char const * const * cucul_get_font_list(void)
  273. {
  274. static char const * const list[] =
  275. {
  276. "Monospace 9",
  277. "Monospace Bold 12",
  278. NULL
  279. };
  280. return list;
  281. }
  282. /** \brief Get a font's standard glyph width.
  283. *
  284. * Return the standard value for the current font's glyphs. Most glyphs in
  285. * the font will have this width, except fullwidth characters.
  286. *
  287. * This function never fails.
  288. *
  289. * \param f The font, as returned by cucul_load_font()
  290. * \return The standard glyph width.
  291. */
  292. unsigned int cucul_get_font_width(cucul_font_t const *f)
  293. {
  294. return f->header.width;
  295. }
  296. /** \brief Get a font's standard glyph height.
  297. *
  298. * Returns the standard value for the current font's glyphs. Most glyphs in
  299. * the font will have this height.
  300. *
  301. * This function never fails.
  302. *
  303. * \param f The font, as returned by cucul_load_font()
  304. * \return The standard glyph height.
  305. */
  306. unsigned int cucul_get_font_height(cucul_font_t const *f)
  307. {
  308. return f->header.height;
  309. }
  310. /** \brief Get a font's list of supported glyphs.
  311. *
  312. * This function returns the list of Unicode blocks supported by the
  313. * given font. The list is a zero-terminated list of indices. Here is
  314. * an example:
  315. *
  316. * \code
  317. * {
  318. * 0x0000, 0x0080, // Basic latin: A, B, C, a, b, c
  319. * 0x0080, 0x0100, // Latin-1 supplement: "A, 'e, ^u
  320. * 0x0530, 0x0590, // Armenian
  321. * 0x0000, 0x0000, // END
  322. * };
  323. * \endcode
  324. *
  325. * This function never fails.
  326. *
  327. * \param f The font, as returned by cucul_load_font()
  328. * \return The list of Unicode blocks supported by the font.
  329. */
  330. unsigned long int const *cucul_get_font_blocks(cucul_font_t const *f)
  331. {
  332. return (unsigned long int const *)f->user_block_list;
  333. }
  334. /** \brief Free a font structure.
  335. *
  336. * This function frees all data allocated by cucul_load_font(). The
  337. * font structure is no longer usable by other libcucul functions. Once
  338. * this function has returned, the memory area that was given to
  339. * cucul_load_font() can be freed.
  340. *
  341. * This function never fails.
  342. *
  343. * \param f The font, as returned by cucul_load_font()
  344. * \return This function always returns 0.
  345. */
  346. int cucul_free_font(cucul_font_t *f)
  347. {
  348. free(f->glyph_list);
  349. free(f->user_block_list);
  350. free(f->block_list);
  351. free(f);
  352. return 0;
  353. }
  354. /** \brief Render the canvas onto an image buffer.
  355. *
  356. * This function renders the given canvas on an image buffer using a specific
  357. * font. The pixel format is fixed (32-bit ARGB, 8 bits for each component).
  358. *
  359. * The required image width can be computed using
  360. * cucul_get_canvas_width() and cucul_get_font_width(). The required
  361. * height can be computed using cucul_get_canvas_height() and
  362. * cucul_get_font_height().
  363. *
  364. * Glyphs that do not fit in the image buffer are currently not rendered at
  365. * all. They may be cropped instead in future versions.
  366. *
  367. * This function never fails.
  368. *
  369. * \param cv The canvas to render
  370. * \param f The font, as returned by cucul_load_font()
  371. * \param buf The image buffer
  372. * \param width The width (in pixels) of the image buffer
  373. * \param height The height (in pixels) of the image buffer
  374. * \param pitch The pitch (in bytes) of an image buffer line.
  375. * \return This function always returns 0.
  376. */
  377. int cucul_render_canvas(cucul_canvas_t const *cv, cucul_font_t const *f,
  378. void *buf, unsigned int width,
  379. unsigned int height, unsigned int pitch)
  380. {
  381. uint8_t *glyph = NULL;
  382. unsigned int x, y, xmax, ymax;
  383. if(f->header.bpp != 8)
  384. glyph = malloc(f->header.width * 2 * f->header.height);
  385. if(width < cv->width * f->header.width)
  386. xmax = width / f->header.width;
  387. else
  388. xmax = cv->width;
  389. if(height < cv->height * f->header.height)
  390. ymax = height / f->header.height;
  391. else
  392. ymax = cv->height;
  393. for(y = 0; y < ymax; y++)
  394. {
  395. for(x = 0; x < xmax; x++)
  396. {
  397. uint8_t argb[8];
  398. unsigned int starty = y * f->header.height;
  399. unsigned int startx = x * f->header.width;
  400. uint32_t ch = cv->chars[y * cv->width + x];
  401. uint32_t attr = cv->attrs[y * cv->width + x];
  402. unsigned int b, i, j;
  403. struct glyph_info *g;
  404. /* Find the Unicode block where our glyph lies */
  405. for(b = 0; b < f->header.blocks; b++)
  406. {
  407. if(ch < f->block_list[b].start)
  408. {
  409. b = f->header.blocks;
  410. break;
  411. }
  412. if(ch < f->block_list[b].stop)
  413. break;
  414. }
  415. /* Glyph not in font? Skip it. */
  416. if(b == f->header.blocks)
  417. continue;
  418. g = &f->glyph_list[f->block_list[b].index
  419. + ch - f->block_list[b].start];
  420. cucul_attr_to_argb64(attr, argb);
  421. /* Step 1: unpack glyph */
  422. switch(f->header.bpp)
  423. {
  424. case 8:
  425. glyph = f->font_data + g->data_offset;
  426. break;
  427. case 4:
  428. unpack_glyph4(glyph, f->font_data + g->data_offset,
  429. g->width * g->height);
  430. break;
  431. case 2:
  432. unpack_glyph2(glyph, f->font_data + g->data_offset,
  433. g->width * g->height);
  434. break;
  435. case 1:
  436. unpack_glyph1(glyph, f->font_data + g->data_offset,
  437. g->width * g->height);
  438. break;
  439. }
  440. /* Step 2: render glyph using colour attribute */
  441. for(j = 0; j < g->height; j++)
  442. {
  443. uint8_t *line = buf;
  444. line += (starty + j) * pitch + 4 * startx;
  445. for(i = 0; i < g->width; i++)
  446. {
  447. uint8_t *pixel = line + 4 * i;
  448. uint32_t p, q, t;
  449. p = glyph[j * g->width + i];
  450. q = 0xff - p;
  451. for(t = 0; t < 4; t++)
  452. pixel[t] = (((q * argb[t]) + (p * argb[4 + t])) / 0xf);
  453. }
  454. }
  455. }
  456. }
  457. if(f->header.bpp != 8)
  458. free(glyph);
  459. return 0;
  460. }