You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

преди 19 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  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. }