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

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