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

font.c 16 KiB

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