You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

519 lines
16 KiB

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