25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

277 lines
7.4 KiB

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