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.

преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  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 const *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 const *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 const *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 const *cv, cucul_font_t const *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_argb64(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. }