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

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