source: libcaca/trunk/cucul/font.c @ 1148

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