source: libcaca/trunk/cucul/canvas.c @ 958

Last change on this file since 958 was 958, checked in by Sam Hocevar, 14 years ago
  • Changed cucul_putchar's prototype so that it accepts a 32-bit unsigned int which shall be used as an UTF-32 character. We do not have any casting problems due to the signedness of chars because all characters were ASCII (ie. <= 0x7f) beforehands.
  • Property svn:keywords set to Id
File size: 7.1 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: canvas.c 958 2006-05-18 06:23:47Z 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 various canvas handling functions such as character
16 *  and string drawing.
17 */
18
19#include "config.h"
20#include "common.h"
21
22#if !defined(__KERNEL__)
23#   include <stdio.h> /* BUFSIZ */
24#   include <string.h>
25#   include <stdlib.h>
26#   include <stdarg.h>
27#   if defined(HAVE_ERRNO_H)
28#       include <errno.h>
29#   endif
30#   if defined(HAVE_UNISTD_H)
31#       include <unistd.h>
32#   endif
33#   if defined(HAVE_SIGNAL_H)
34#       include <signal.h>
35#   endif
36#   if defined(HAVE_SYS_IOCTL_H)
37#       include <sys/ioctl.h>
38#   endif
39#endif
40
41#include "cucul.h"
42#include "cucul_internals.h"
43
44/** \brief Print an ASCII or Unicode character.
45 *
46 *  This function prints an ASCII or Unicode character at the given
47 *  coordinates, using the default foreground and background values.
48 *
49 *  If the coordinates are outside the canvas boundaries, nothing is printed.
50 *  If the character value is a non-printable character or is outside the
51 *  UTF-32 range, it is replaced with a space. To print a sequence of bytes
52 *  forming an UTF-8 character instead of an UTF-32 character, use the
53 *  cucul_putstr() function instead.
54 *
55 *  This function never fails.
56 *
57 *  \param cv A handle to the libcucul canvas.
58 *  \param x X coordinate.
59 *  \param y Y coordinate.
60 *  \param ch The character to print.
61 *  \return This function always returns 0.
62 */
63int cucul_putchar(cucul_canvas_t *cv, int x, int y, unsigned long int ch)
64{
65    if(x < 0 || x >= (int)cv->width || y < 0 || y >= (int)cv->height)
66        return 0;
67
68    if((unsigned char)ch < 0x20)
69        ch = 0x20;
70
71    cv->chars[x + y * cv->width] = ch;
72    cv->attr[x + y * cv->width] = (cv->bgcolor << 16) | cv->fgcolor;
73
74    return 0;
75}
76
77/** \brief Print a string.
78 *
79 *  This function prints an UTF-8 string at the given coordinates, using the
80 *  default foreground and background values. The coordinates may be outside
81 *  the canvas boundaries (eg. a negative Y coordinate) and the string will
82 *  be cropped accordingly if it is too long.
83 *
84 *  This function never fails.
85 *
86 *  \param cv A handle to the libcucul canvas.
87 *  \param x X coordinate.
88 *  \param y Y coordinate.
89 *  \param s The string to print.
90 *  \return This function always returns 0.
91 */
92int cucul_putstr(cucul_canvas_t *cv, int x, int y, char const *s)
93{
94    uint32_t *chars, *attr;
95    unsigned int len;
96
97    if(y < 0 || y >= (int)cv->height || x >= (int)cv->width)
98        return 0;
99
100    len = _cucul_strlen_utf8(s);
101
102    if(x < 0)
103    {
104        if(len < (unsigned int)-x)
105            return 0;
106        len -= -x;
107        s = _cucul_skip_utf8(s, -x);
108        x = 0;
109    }
110
111    chars = cv->chars + x + y * cv->width;
112    attr = cv->attr + x + y * cv->width;
113
114    if(x + len >= cv->width)
115        len = cv->width - x;
116
117    while(len)
118    {
119        *chars++ = _cucul_utf8_to_utf32(s);
120        *attr++ = (cv->bgcolor << 16) | cv->fgcolor;
121
122        s = _cucul_skip_utf8(s, 1);
123        len--;
124    }
125
126    return 0;
127}
128
129/** \brief Print a formated string.
130 *
131 *  This function formats a string at the given coordinates, using the
132 *  default foreground and background values. The coordinates may be outside
133 *  the canvas boundaries (eg. a negative Y coordinate) and the string will
134 *  be cropped accordingly if it is too long. The syntax of the format
135 *  string is the same as for the C printf() function.
136 *
137 *  This function never fails.
138 *
139 *  \param cv A handle to the libcucul canvas.
140 *  \param x X coordinate.
141 *  \param y Y coordinate.
142 *  \param format The format string to print.
143 *  \param ... Arguments to the format string.
144 *  \return This function always returns 0.
145 */
146int cucul_printf(cucul_canvas_t *cv, int x, int y, char const *format, ...)
147{
148    char tmp[BUFSIZ];
149    char *buf = tmp;
150    va_list args;
151
152    if(y < 0 || y >= (int)cv->height || x >= (int)cv->width)
153        return 0;
154
155    if(cv->width - x + 1 > BUFSIZ)
156        buf = malloc(cv->width - x + 1);
157
158    va_start(args, format);
159#if defined(HAVE_VSNPRINTF)
160    vsnprintf(buf, cv->width - x + 1, format, args);
161#else
162    vsprintf(buf, format, args);
163#endif
164    buf[cv->width - x] = '\0';
165    va_end(args);
166
167    cucul_putstr(cv, x, y, buf);
168
169    if(buf != tmp)
170        free(buf);
171
172    return 0;
173}
174
175/** \brief Clear the canvas.
176 *
177 *  This function clears the canvas using the current background colour.
178 *
179 *  This function never fails.
180 *
181 *  \param cv The canvas to clear.
182 *  \return This function always returns 0.
183 */
184int cucul_clear_canvas(cucul_canvas_t *cv)
185{
186    uint32_t color = (cv->bgcolor << 16) | cv->fgcolor;
187    unsigned int n;
188
189    /* We could use SLsmg_cls() etc., but drawing empty lines is much faster */
190    for(n = cv->width * cv->height; n--; )
191    {
192        cv->chars[n] = (uint32_t)' ';
193        cv->attr[n] = color;
194    }
195
196    return 0;
197}
198
199/** \brief Blit a canvas onto another one.
200 *
201 *  This function blits a canvas onto another one at the given coordinates.
202 *  An optional mask canvas can be used.
203 *
204 *  If an error occurs, -1 is returned and \b errno is set accordingly:
205 *  - \c EINVAL A mask was specified but the mask size and source canvas
206 *    size do not match.
207 *
208 *  \param dst The destination canvas.
209 *  \param x X coordinate.
210 *  \param y Y coordinate.
211 *  \param src The source canvas.
212 *  \param mask The mask canvas.
213 *  \return 0 in case of success, -1 if an error occurred.
214 */
215int cucul_blit(cucul_canvas_t *dst, int x, int y,
216               cucul_canvas_t const *src, cucul_canvas_t const *mask)
217{
218    int i, j, starti, startj, endi, endj;
219
220    if(mask && (src->width != mask->width || src->height != mask->height))
221    {
222#if defined(HAVE_ERRNO_H)
223        errno = EINVAL;
224#endif
225        return -1;
226    }
227
228    starti = x < 0 ? -x : 0;
229    startj = y < 0 ? -y : 0;
230    endi = (x + src->width >= dst->width) ? dst->width - x : src->width;
231    endj = (y + src->height >= dst->height) ? dst->height - y : src->height;
232
233    if(starti >= endi || startj >= endj)
234        return 0;
235
236    for(j = startj; j < endj; j++)
237    {
238        if(mask)
239        {
240            for(i = starti; i < endi; i++)
241            {
242                if(mask->chars[j * src->width + i] == (uint32_t)' ')
243                    continue;
244
245                dst->chars[(j + y) * dst->width + (i + x)]
246                                             = src->chars[j * src->width + i];
247                dst->attr[(j + y) * dst->width + (i + x)]
248                                             = src->attr[j * src->width + i];
249            }
250        }
251        else
252        {
253            memcpy(dst->chars + (j + y) * dst->width + starti + x,
254                   src->chars + j * src->width + starti,
255                   (endi - starti) * 4);
256            memcpy(dst->attr + (j + y) * dst->width + starti + x,
257                   src->attr + j * src->width + starti,
258                   (endi - starti) * 4);
259        }
260    }
261
262    return 0;
263}
264
Note: See TracBrowser for help on using the repository browser.