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.
 
 
 
 
 
 

434 line
13 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; 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. #if !defined(__KERNEL__)
  18. # if defined(HAVE_ENDIAN_H)
  19. # include <endian.h>
  20. # endif
  21. # include <stdio.h>
  22. # include <stdlib.h>
  23. # include <string.h>
  24. # include <arpa/inet.h>
  25. #endif
  26. #include "cucul.h"
  27. #include "cucul_internals.h"
  28. /* Internal fonts */
  29. #include "font_mono9.h"
  30. #include "font_monobold12.h"
  31. /* Helper structure for font loading */
  32. struct font_header
  33. {
  34. uint32_t control_size, data_size;
  35. uint16_t version, blocks;
  36. uint32_t glyphs;
  37. uint16_t bpp, width, height, flags;
  38. };
  39. struct block_info
  40. {
  41. uint32_t start, stop, index;
  42. };
  43. struct glyph_info
  44. {
  45. uint16_t width, height;
  46. uint32_t data_offset;
  47. };
  48. struct cucul_font
  49. {
  50. struct font_header header;
  51. struct block_info *block_list;
  52. struct glyph_info *glyph_list;
  53. uint8_t *font_data;
  54. uint8_t *private;
  55. };
  56. #define DECLARE_UNPACKGLYPH(bpp) \
  57. static inline void \
  58. unpack_glyph ## bpp(uint8_t *glyph, uint8_t *packed_data, \
  59. unsigned int n) \
  60. { \
  61. unsigned int i; \
  62. \
  63. for(i = 0; i < n; i++) \
  64. { \
  65. uint8_t pixel = packed_data[i / (8 / bpp)]; \
  66. pixel >>= bpp * ((8 / bpp) - 1 - (i % (8 / bpp))); \
  67. pixel %= (1 << bpp); \
  68. pixel *= 0xff / ((1 << bpp) - 1); \
  69. *glyph++ = pixel; \
  70. } \
  71. }
  72. DECLARE_UNPACKGLYPH(4)
  73. DECLARE_UNPACKGLYPH(2)
  74. DECLARE_UNPACKGLYPH(1)
  75. /** \brief Load a font from memory for future use.
  76. *
  77. * This function loads a font and returns a handle to its internal
  78. * structure. The handle can then be used with \e cucul_render_canvas()
  79. * for bitmap output.
  80. *
  81. * Internal fonts can also be loaded: if \e size is set to 0, \e data must
  82. * be a string containing the internal font name.
  83. *
  84. * If \e size is non-zero, the \e size bytes of memory at address \e data
  85. * are loaded as a font. This memory are must not be freed by the calling
  86. * program until the font handle has been freed with \e cucul_free_font().
  87. *
  88. * \param data The memory area containing the font or its name.
  89. * \param size The size of the memory area, or 0 if the font name is given.
  90. * \return A font handle or NULL in case of error.
  91. */
  92. struct cucul_font *cucul_load_font(void const *data, unsigned int size)
  93. {
  94. struct cucul_font *f;
  95. unsigned int i;
  96. if(size == 0)
  97. {
  98. if(!strcasecmp(data, "Monospace 9"))
  99. return cucul_load_font(mono9_data, mono9_size);
  100. if(!strcasecmp(data, "Monospace Bold 12"))
  101. return cucul_load_font(monobold12_data, monobold12_size);
  102. return NULL;
  103. }
  104. if(size < sizeof(struct font_header))
  105. return NULL;
  106. f = malloc(sizeof(struct cucul_font));
  107. f->private = (void *)(uintptr_t)data;
  108. memcpy(&f->header, f->private + 8, sizeof(struct font_header));
  109. f->header.control_size = htonl(f->header.control_size);
  110. f->header.data_size = htonl(f->header.data_size);
  111. f->header.version = htons(f->header.version);
  112. f->header.blocks = htons(f->header.blocks);
  113. f->header.glyphs = htonl(f->header.glyphs);
  114. f->header.bpp = htons(f->header.bpp);
  115. f->header.width = htons(f->header.width);
  116. f->header.height = htons(f->header.height);
  117. f->header.flags = htons(f->header.flags);
  118. if(size != 8 + f->header.control_size + f->header.data_size
  119. || (f->header.bpp != 8 && f->header.bpp != 4 &&
  120. f->header.bpp != 2 && f->header.bpp != 1)
  121. || (flags & 1) == 0)
  122. {
  123. free(f);
  124. return NULL;
  125. }
  126. f->block_list = malloc(f->header.blocks * sizeof(struct block_info));
  127. memcpy(f->block_list,
  128. f->private + 8 + sizeof(struct font_header),
  129. f->header.blocks * sizeof(struct block_info));
  130. for(i = 0; i < f->header.blocks; i++)
  131. {
  132. f->block_list[i].start = htonl(f->block_list[i].start);
  133. f->block_list[i].stop = htonl(f->block_list[i].stop);
  134. f->block_list[i].index = htonl(f->block_list[i].index);
  135. if(f->block_list[i].start > f->block_list[i].stop
  136. || (i > 0 && f->block_list[i].start < f->block_list[i - 1].stop)
  137. || f->block_list[i].index >= f->header.glyphs)
  138. {
  139. free(f->block_list);
  140. free(f);
  141. return NULL;
  142. }
  143. }
  144. f->glyph_list = malloc(f->header.glyphs * sizeof(struct glyph_info));
  145. memcpy(f->glyph_list,
  146. f->private + 8 + sizeof(struct font_header)
  147. + f->header.blocks * sizeof(struct block_info),
  148. f->header.glyphs * sizeof(struct glyph_info));
  149. for(i = 0; i < f->header.glyphs; i++)
  150. {
  151. f->glyph_list[i].width = htons(f->glyph_list[i].width);
  152. f->glyph_list[i].height = htons(f->glyph_list[i].height);
  153. f->glyph_list[i].data_offset = htonl(f->glyph_list[i].data_offset);
  154. if(f->glyph_list[i].data_offset >= f->header.data_size
  155. || f->glyph_list[i].data_offset
  156. + f->glyph_list[i].width * f->glyph_list[i].height *
  157. f->header.bpp / 8 >= f->header.data_size)
  158. {
  159. free(f->glyph_list);
  160. free(f->block_list);
  161. free(f);
  162. return NULL;
  163. }
  164. }
  165. f->font_data = f->private + 8 + f->header.control_size;
  166. return f;
  167. }
  168. /**
  169. * \brief Get available builtin fonts
  170. *
  171. * Return a list of available builtin fonts. The list is a NULL-terminated
  172. * array of strings.
  173. *
  174. * \return An array of strings.
  175. */
  176. char const * const * cucul_get_font_list(void)
  177. {
  178. static char const * const list[] =
  179. {
  180. "Monospace 9",
  181. "Monospace Bold 12",
  182. NULL
  183. };
  184. return list;
  185. }
  186. /** \brief Get a font's maximum glyph width.
  187. *
  188. * This function returns the maximum value for the current font's glyphs
  189. *
  190. * \param f The font, as returned by \e cucul_load_font()
  191. * \return The maximum glyph width.
  192. */
  193. unsigned int cucul_get_font_width(struct cucul_font *f)
  194. {
  195. return f->header.width;
  196. }
  197. /** \brief Get a font's maximum glyph height.
  198. *
  199. * This function returns the maximum value for the current font's glyphs
  200. *
  201. * \param f The font, as returned by \e cucul_load_font()
  202. * \return The maximum glyph height.
  203. */
  204. unsigned int cucul_get_font_height(struct cucul_font *f)
  205. {
  206. return f->header.height;
  207. }
  208. /** \brief Free a font structure.
  209. *
  210. * This function frees all data allocated by \e cucul_load_font(). The
  211. * font structure is no longer usable by other libcucul functions. Once
  212. * this function has returned, the memory area that was given to
  213. * \e cucul_load_font() can be freed.
  214. *
  215. * \param f The font, as returned by \e cucul_load_font()
  216. */
  217. void cucul_free_font(struct cucul_font *f)
  218. {
  219. free(f->glyph_list);
  220. free(f->block_list);
  221. free(f);
  222. }
  223. /** \brief Render the canvas onto an image buffer.
  224. *
  225. * This function renders the given canvas on an image buffer using a specific
  226. * font. The pixel format is fixed (32-bit ARGB, 8 bits for each component).
  227. *
  228. * The required image width can be computed using \e cucul_get_width(qq) and
  229. * \e cucul_get_font_width(f). The required height can be computed using
  230. * \e cucul_get_height(qq) and \e cucul_get_font_height(f).
  231. *
  232. * Glyphs that do not fit in the image buffer are currently not rendered at
  233. * all. They may be cropped instead in future versions.
  234. *
  235. * \param qq The canvas to render
  236. * \param f The font, as returned by \e cucul_load_font()
  237. * \param buf The image buffer
  238. * \param width The width (in pixels) of the image buffer
  239. * \param height The height (in pixels) of the image buffer
  240. * \param pitch The pitch (in bytes) of an image buffer line.
  241. */
  242. void cucul_render_canvas(cucul_t *qq, struct cucul_font *f,
  243. unsigned char *buf, unsigned int width,
  244. unsigned int height, unsigned int pitch)
  245. {
  246. uint8_t *glyph = NULL;
  247. unsigned int x, y, xmax, ymax;
  248. if(f->header.bpp != 8)
  249. glyph = malloc(f->header.width * f->header.height);
  250. if(width < qq->width * f->header.width)
  251. xmax = width / f->header.width;
  252. else
  253. xmax = qq->width;
  254. if(height < qq->height * f->header.height)
  255. ymax = height / f->header.height;
  256. else
  257. ymax = qq->height;
  258. for(y = 0; y < ymax; y++)
  259. {
  260. for(x = 0; x < xmax; x++)
  261. {
  262. uint8_t argb[8];
  263. unsigned int starty = y * f->header.height;
  264. unsigned int startx = x * f->header.width;
  265. uint32_t ch = qq->chars[y * qq->width + x];
  266. uint32_t attr = qq->attr[y * qq->width + x];
  267. unsigned int b, i, j;
  268. struct glyph_info *g;
  269. /* Find the Unicode block where our glyph lies */
  270. for(b = 0; b < f->header.blocks; b++)
  271. {
  272. if(ch < f->block_list[b].start)
  273. {
  274. b = f->header.blocks;
  275. break;
  276. }
  277. if(ch < f->block_list[b].stop)
  278. break;
  279. }
  280. /* Glyph not in font? Skip it. */
  281. if(b == f->header.blocks)
  282. continue;
  283. g = &f->glyph_list[f->block_list[b].index
  284. + ch - f->block_list[b].start];
  285. _cucul_argb32_to_argb4(attr, argb);
  286. /* Step 1: unpack glyph */
  287. switch(f->header.bpp)
  288. {
  289. case 8:
  290. glyph = f->font_data + g->data_offset;
  291. break;
  292. case 4:
  293. unpack_glyph4(glyph, f->font_data + g->data_offset,
  294. g->width * g->height);
  295. break;
  296. case 2:
  297. unpack_glyph2(glyph, f->font_data + g->data_offset,
  298. g->width * g->height);
  299. break;
  300. case 1:
  301. unpack_glyph1(glyph, f->font_data + g->data_offset,
  302. g->width * g->height);
  303. break;
  304. }
  305. /* Step 2: render glyph using colour attribute */
  306. for(j = 0; j < g->height; j++)
  307. {
  308. uint8_t *line = buf + (starty + j) * pitch + 4 * startx;
  309. for(i = 0; i < g->width; i++)
  310. {
  311. uint8_t *pixel = line + 4 * i;
  312. uint32_t p, q, t;
  313. p = glyph[j * g->width + i];
  314. q = 0xff - p;
  315. for(t = 0; t < 4; t++)
  316. pixel[t] = (((q * argb[t]) + (p * argb[4 + t])) / 0xf);
  317. }
  318. }
  319. }
  320. }
  321. if(f->header.bpp != 8)
  322. free(glyph);
  323. }
  324. /*
  325. * The libcaca font format, version 1
  326. * ----------------------------------
  327. *
  328. * All types are big endian.
  329. *
  330. * struct
  331. * {
  332. * uint8_t caca_header[4]; // "CACA"
  333. * uint8_t caca_file_type[4]; // "FONT"
  334. *
  335. * font_header:
  336. * uint32_t control_size; // Control size (font_data - font_header)
  337. * uint32_t data_size; // Data size (EOF - font_data)
  338. *
  339. * uint16_t version; // Font format version
  340. * // bit 0: set to 1 if font is compatible
  341. * // with version 1 of the format
  342. * // bits 1-15: unused yet, must be 0
  343. *
  344. * uint16_t blocks; // Number of blocks in the font
  345. * uint32_t glyphs; // Total number of glyphs in the font
  346. *
  347. * uint16_t bpp; // Bits per pixel for glyph data (valid
  348. * // Values are 1, 2, 4 and 8)
  349. * uint16_t width; // Maximum glyph width
  350. * uint16_t height; // Maximum glyph height
  351. *
  352. * uint16_t flags; // Feature flags
  353. * // bit 0: set to 1 if font is fixed width
  354. * // bits 1-15: unused yet, must be 0
  355. *
  356. * block_info:
  357. * struct
  358. * {
  359. * uint32_t start; // Unicode index of the first glyph
  360. * uint32_t stop; // Unicode index of the last glyph + 1
  361. * uint32_t index; // Glyph info index of the first glyph
  362. * }
  363. * block_list[blocks];
  364. *
  365. * glyph_info:
  366. * struct
  367. * {
  368. * uint16_t width; // Glyph width in pixels
  369. * uint16_t height; // Glyph height in pixels
  370. * uint32_t data_offset; // Offset (starting from data) to the data
  371. * // for the first character
  372. * }
  373. * glyph_list[glyphs];
  374. *
  375. * extension_1:
  376. * extension_2:
  377. * ...
  378. * extension_N:
  379. * ... // reserved for future use
  380. *
  381. * font_data:
  382. * uint8_t data[data_size]; // glyph data
  383. * };
  384. */