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

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