Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 
 
 
 

351 рядки
9.7 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 or Unicode character.
  40. *
  41. * This function prints an ASCII or Unicode character at the given
  42. * coordinates, using the default foreground and background values.
  43. *
  44. * If the coordinates are outside the canvas boundaries, nothing is printed.
  45. * If the character value is a non-printable character or is outside the
  46. * UTF-32 range, it is replaced with a space. To print a sequence of bytes
  47. * forming an UTF-8 character instead of an UTF-32 character, use the
  48. * cucul_putstr() function instead.
  49. *
  50. * This function never fails.
  51. *
  52. * \param cv A handle to the libcucul canvas.
  53. * \param x X coordinate.
  54. * \param y Y coordinate.
  55. * \param ch The character to print.
  56. * \return This function always returns 0.
  57. */
  58. int cucul_putchar(cucul_canvas_t *cv, int x, int y, unsigned long int ch)
  59. {
  60. if(x < 0 || x >= (int)cv->width || y < 0 || y >= (int)cv->height)
  61. return 0;
  62. if(ch < 0x20)
  63. ch = 0x20;
  64. cv->chars[x + y * cv->width] = ch;
  65. cv->attr[x + y * cv->width] = (cv->bgcolor << 16) | cv->fgcolor;
  66. return 0;
  67. }
  68. /** \brief Get the Unicode character at the given coordinates.
  69. *
  70. * This function gets the ASCII or Unicode value of the character at
  71. * the given coordinates. If the value is less or equal to 127 (0x7f),
  72. * the character can be printed as ASCII. Otherise, it must be handled
  73. * as a UTF-32 value.
  74. *
  75. * If the coordinates are outside the canvas boundaries, a space (0x20)
  76. * is returned.
  77. *
  78. * This function never fails.
  79. *
  80. * \param cv A handle to the libcucul canvas.
  81. * \param x X coordinate.
  82. * \param y Y coordinate.
  83. * \param ch The requested character value.
  84. * \return The character always returns 0.
  85. */
  86. unsigned long int cucul_getchar(cucul_canvas_t *cv, int x, int y)
  87. {
  88. if(x < 0 || x >= (int)cv->width || y < 0 || y >= (int)cv->height)
  89. return (unsigned char)' ';
  90. return (unsigned long int)cv->chars[x + y * cv->width];
  91. }
  92. /** \brief Print a string.
  93. *
  94. * This function prints an UTF-8 string at the given coordinates, using the
  95. * default foreground and background values. The coordinates may be outside
  96. * the canvas boundaries (eg. a negative Y coordinate) and the string will
  97. * be cropped accordingly if it is too long.
  98. *
  99. * This function never fails.
  100. *
  101. * \param cv A handle to the libcucul canvas.
  102. * \param x X coordinate.
  103. * \param y Y coordinate.
  104. * \param s The string to print.
  105. * \return This function always returns 0.
  106. */
  107. int cucul_putstr(cucul_canvas_t *cv, int x, int y, char const *s)
  108. {
  109. uint32_t *chars, *attr;
  110. unsigned int len;
  111. if(y < 0 || y >= (int)cv->height || x >= (int)cv->width)
  112. return 0;
  113. len = _cucul_strlen_utf8(s);
  114. if(x < 0)
  115. {
  116. if(len < (unsigned int)-x)
  117. return 0;
  118. len -= -x;
  119. s = _cucul_skip_utf8(s, -x);
  120. x = 0;
  121. }
  122. chars = cv->chars + x + y * cv->width;
  123. attr = cv->attr + x + y * cv->width;
  124. if(x + len >= cv->width)
  125. len = cv->width - x;
  126. while(len)
  127. {
  128. *chars++ = cucul_utf8_to_utf32(s, NULL);
  129. *attr++ = (cv->bgcolor << 16) | cv->fgcolor;
  130. s = _cucul_skip_utf8(s, 1);
  131. len--;
  132. }
  133. return 0;
  134. }
  135. /** \brief Print a formated string.
  136. *
  137. * This function formats a string at the given coordinates, using the
  138. * default foreground and background values. The coordinates may be outside
  139. * the canvas boundaries (eg. a negative Y coordinate) and the string will
  140. * be cropped accordingly if it is too long. The syntax of the format
  141. * string is the same as for the C printf() function.
  142. *
  143. * This function never fails.
  144. *
  145. * \param cv A handle to the libcucul canvas.
  146. * \param x X coordinate.
  147. * \param y Y coordinate.
  148. * \param format The format string to print.
  149. * \param ... Arguments to the format string.
  150. * \return This function always returns 0.
  151. */
  152. int cucul_printf(cucul_canvas_t *cv, int x, int y, char const *format, ...)
  153. {
  154. char tmp[BUFSIZ];
  155. char *buf = tmp;
  156. va_list args;
  157. if(y < 0 || y >= (int)cv->height || x >= (int)cv->width)
  158. return 0;
  159. if(cv->width - x + 1 > BUFSIZ)
  160. buf = malloc(cv->width - x + 1);
  161. va_start(args, format);
  162. #if defined(HAVE_VSNPRINTF)
  163. vsnprintf(buf, cv->width - x + 1, format, args);
  164. #else
  165. vsprintf(buf, format, args);
  166. #endif
  167. buf[cv->width - x] = '\0';
  168. va_end(args);
  169. cucul_putstr(cv, x, y, buf);
  170. if(buf != tmp)
  171. free(buf);
  172. return 0;
  173. }
  174. /** \brief Clear the canvas.
  175. *
  176. * This function clears the canvas using the current background colour.
  177. *
  178. * This function never fails.
  179. *
  180. * \param cv The canvas to clear.
  181. * \return This function always returns 0.
  182. */
  183. int cucul_clear_canvas(cucul_canvas_t *cv)
  184. {
  185. uint32_t color = (cv->bgcolor << 16) | cv->fgcolor;
  186. unsigned int n;
  187. /* We could use SLsmg_cls() etc., but drawing empty lines is much faster */
  188. for(n = cv->width * cv->height; n--; )
  189. {
  190. cv->chars[n] = (uint32_t)' ';
  191. cv->attr[n] = color;
  192. }
  193. return 0;
  194. }
  195. /** \brief Blit a canvas onto another one.
  196. *
  197. * This function blits a canvas onto another one at the given coordinates.
  198. * An optional mask canvas can be used.
  199. *
  200. * If an error occurs, -1 is returned and \b errno is set accordingly:
  201. * - \c EINVAL A mask was specified but the mask size and source canvas
  202. * size do not match.
  203. *
  204. * \param dst The destination canvas.
  205. * \param x X coordinate.
  206. * \param y Y coordinate.
  207. * \param src The source canvas.
  208. * \param mask The mask canvas.
  209. * \return 0 in case of success, -1 if an error occurred.
  210. */
  211. int cucul_blit(cucul_canvas_t *dst, int x, int y,
  212. cucul_canvas_t const *src, cucul_canvas_t const *mask)
  213. {
  214. int i, j, starti, startj, endi, endj;
  215. if(mask && (src->width != mask->width || src->height != mask->height))
  216. {
  217. #if defined(HAVE_ERRNO_H)
  218. errno = EINVAL;
  219. #endif
  220. return -1;
  221. }
  222. starti = x < 0 ? -x : 0;
  223. startj = y < 0 ? -y : 0;
  224. endi = (x + src->width >= dst->width) ? dst->width - x : src->width;
  225. endj = (y + src->height >= dst->height) ? dst->height - y : src->height;
  226. if((unsigned int)starti > src->width || (unsigned int)startj > src->height
  227. || starti >= endi || startj >= endj)
  228. return 0;
  229. for(j = startj; j < endj; j++)
  230. {
  231. if(mask)
  232. {
  233. for(i = starti; i < endi; i++)
  234. {
  235. if(mask->chars[j * src->width + i] == (uint32_t)' ')
  236. continue;
  237. dst->chars[(j + y) * dst->width + (i + x)]
  238. = src->chars[j * src->width + i];
  239. dst->attr[(j + y) * dst->width + (i + x)]
  240. = src->attr[j * src->width + i];
  241. }
  242. }
  243. else
  244. {
  245. memcpy(dst->chars + (j + y) * dst->width + starti + x,
  246. src->chars + j * src->width + starti,
  247. (endi - starti) * 4);
  248. memcpy(dst->attr + (j + y) * dst->width + starti + x,
  249. src->attr + j * src->width + starti,
  250. (endi - starti) * 4);
  251. }
  252. }
  253. return 0;
  254. }
  255. /** \brief Set a canvas' new boundaries.
  256. *
  257. * This function sets new boundaries for a canvas. It can be used to crop a
  258. * canvas, to expand it or for combinations of both actions.
  259. *
  260. * If an error occurs, -1 is returned and \b errno is set accordingly:
  261. * - \c EBUSY The canvas is in use by a display driver and cannot be resized.
  262. * - \c ENOMEM Not enough memory for the requested canvas size. If this
  263. * happens, the canvas handle becomes invalid and should not be used.
  264. *
  265. * \param cv The canvas to crop.
  266. * \param x X coordinate of the top-left corner.
  267. * \param y Y coordinate of the top-left corner.
  268. * \param w The width of the cropped area.
  269. * \param h The height of the cropped area.
  270. * \return 0 in case of success, -1 if an error occurred.
  271. */
  272. int cucul_set_canvas_boundaries(cucul_canvas_t *cv, int x, int y,
  273. unsigned int w, unsigned int h)
  274. {
  275. cucul_canvas_t *new;
  276. unsigned int f, saved_f, framecount;
  277. if(cv->refcount)
  278. {
  279. #if defined(HAVE_ERRNO_H)
  280. errno = EBUSY;
  281. #endif
  282. return -1;
  283. }
  284. new = cucul_create_canvas(w, h);
  285. framecount = cucul_get_canvas_frame_count(cv);
  286. saved_f = cv->frame;
  287. for(f = 0; f < framecount; f++)
  288. {
  289. if(f)
  290. cucul_create_canvas_frame(new, framecount);
  291. cucul_set_canvas_frame(cv, f);
  292. cucul_set_canvas_frame(new, f);
  293. cucul_blit(new, -x, -y, cv, NULL);
  294. free(cv->allchars[f]);
  295. free(cv->allattr[f]);
  296. }
  297. free(cv->allchars);
  298. free(cv->allattr);
  299. memcpy(cv, new, sizeof(cucul_canvas_t));
  300. free(new);
  301. cucul_set_canvas_frame(cv, saved_f);
  302. return 0;
  303. }