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

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