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

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