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.

преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  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. * Print an ASCII or Unicode character at the given coordinates, using
  42. * the default foreground and background colour values.
  43. *
  44. * If the coordinates are outside the canvas boundaries, nothing is printed.
  45. * If a fullwidth Unicode character gets overwritten, its remaining visible
  46. * parts are replaced with spaces. If the canvas' boundaries would split the
  47. * fullwidth character in two, a space is printed instead.
  48. *
  49. * The behaviour when printing non-printable characters or invalid UTF-32
  50. * characters is undefined. To print a sequence of bytes forming an UTF-8
  51. * character instead of an UTF-32 character, use the cucul_putstr() function.
  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. */
  61. int cucul_putchar(cucul_canvas_t *cv, int x, int y, unsigned long int ch)
  62. {
  63. uint32_t *curchar, *curattr, attr;
  64. int fullwidth;
  65. if(x >= (int)cv->width || y < 0 || y >= (int)cv->height)
  66. return 0;
  67. if(ch == CUCUL_MAGIC_FULLWIDTH)
  68. return 0;
  69. fullwidth = cucul_utf32_is_fullwidth(ch);
  70. if(x == -1 && fullwidth)
  71. {
  72. x = 0;
  73. ch = ' ';
  74. fullwidth = 0;
  75. }
  76. else if(x < 0)
  77. return 0;
  78. curchar = cv->chars + x + y * cv->width;
  79. curattr = cv->attr + x + y * cv->width;
  80. attr = (cv->bgcolor << 16) | cv->fgcolor;
  81. /* When overwriting the right part of a fullwidth character,
  82. * replace its left part with a space. */
  83. if(x && curchar[0] == CUCUL_MAGIC_FULLWIDTH)
  84. curchar[-1] = ' ';
  85. if(fullwidth)
  86. {
  87. if(x + 1 == (int)cv->width)
  88. ch = ' ';
  89. else
  90. {
  91. /* When overwriting the left part of a fullwidth character,
  92. * replace its right part with a space. */
  93. if(x + 2 < (int)cv->width && curchar[2] == CUCUL_MAGIC_FULLWIDTH)
  94. curchar[2] = ' ';
  95. curchar[1] = CUCUL_MAGIC_FULLWIDTH;
  96. curattr[1] = attr;
  97. }
  98. }
  99. else
  100. {
  101. /* When overwriting the left part of a fullwidth character,
  102. * replace its right part with a space. */
  103. if(x + 1 != (int)cv->width && curchar[1] == CUCUL_MAGIC_FULLWIDTH)
  104. curchar[1] = ' ';
  105. }
  106. curchar[0] = ch;
  107. curattr[0] = attr;
  108. return 0;
  109. }
  110. /** \brief Get the Unicode character at the given coordinates.
  111. *
  112. * Get the ASCII or Unicode value of the character at the given
  113. * coordinates. If the value is less or equal to 127 (0x7f),
  114. * the character can be printed as ASCII. Otherise, it must be handled
  115. * as a UTF-32 value.
  116. *
  117. * If the coordinates are outside the canvas boundaries, a space (0x20)
  118. * is returned.
  119. *
  120. * A special exception is when CUCUL_MAGIC_FULLWIDTH is returned. This
  121. * value is guaranteed not to be a valid Unicode character, and indicates
  122. * that the character at the left of the requested one is a fullwidth
  123. * character.
  124. *
  125. * This function never fails.
  126. *
  127. * \param cv A handle to the libcucul canvas.
  128. * \param x X coordinate.
  129. * \param y Y coordinate.
  130. * \param ch The requested character value.
  131. * \return This function always returns 0.
  132. */
  133. unsigned long int cucul_getchar(cucul_canvas_t *cv, int x, int y)
  134. {
  135. if(x < 0 || x >= (int)cv->width || y < 0 || y >= (int)cv->height)
  136. return ' ';
  137. return (unsigned long int)cv->chars[x + y * cv->width];
  138. }
  139. /** \brief Print a string.
  140. *
  141. * Print an UTF-8 string at the given coordinates, using the default
  142. * foreground and background values. The coordinates may be outside the
  143. * canvas boundaries (eg. a negative Y coordinate) and the string will
  144. * be cropped accordingly if it is too long.
  145. *
  146. * See cucul_putchar() for more information on how fullwidth characters
  147. * are handled when overwriting each other or at the canvas' boundaries.
  148. *
  149. * This function never fails.
  150. *
  151. * \param cv A handle to the libcucul canvas.
  152. * \param x X coordinate.
  153. * \param y Y coordinate.
  154. * \param s The string to print.
  155. * \return This function always returns 0.
  156. */
  157. int cucul_putstr(cucul_canvas_t *cv, int x, int y, char const *s)
  158. {
  159. unsigned int read;
  160. if(y < 0 || y >= (int)cv->height || x >= (int)cv->width)
  161. return 0;
  162. while(*s && x < -1)
  163. {
  164. x += cucul_utf32_is_fullwidth(cucul_utf8_to_utf32(s, &read)) ? 2 : 1;
  165. s += read;
  166. }
  167. while(*s && x < (int)cv->width)
  168. {
  169. uint32_t ch = cucul_utf8_to_utf32(s, &read);
  170. cucul_putchar(cv, x, y, ch);
  171. x += cucul_utf32_is_fullwidth(ch) ? 2 : 1;
  172. s += read;
  173. }
  174. return 0;
  175. }
  176. /** \brief Print a formated string.
  177. *
  178. * Format a string at the given coordinates, using the default foreground
  179. * and background values. The coordinates may be outside the canvas
  180. * boundaries (eg. a negative Y coordinate) and the string will be cropped
  181. * accordingly if it is too long. The syntax of the format string is the
  182. * same as for the C printf() function.
  183. *
  184. * This function never fails.
  185. *
  186. * \param cv A handle to the libcucul canvas.
  187. * \param x X coordinate.
  188. * \param y Y coordinate.
  189. * \param format The format string to print.
  190. * \param ... Arguments to the format string.
  191. * \return This function always returns 0.
  192. */
  193. int cucul_printf(cucul_canvas_t *cv, int x, int y, char const *format, ...)
  194. {
  195. char tmp[BUFSIZ];
  196. char *buf = tmp;
  197. va_list args;
  198. if(y < 0 || y >= (int)cv->height || x >= (int)cv->width)
  199. return 0;
  200. if(cv->width - x + 1 > BUFSIZ)
  201. buf = malloc(cv->width - x + 1);
  202. va_start(args, format);
  203. #if defined(HAVE_VSNPRINTF)
  204. vsnprintf(buf, cv->width - x + 1, format, args);
  205. #else
  206. vsprintf(buf, format, args);
  207. #endif
  208. buf[cv->width - x] = '\0';
  209. va_end(args);
  210. cucul_putstr(cv, x, y, buf);
  211. if(buf != tmp)
  212. free(buf);
  213. return 0;
  214. }
  215. /** \brief Clear the canvas.
  216. *
  217. * Clear the canvas using the current foreground and background colours.
  218. *
  219. * This function never fails.
  220. *
  221. * \param cv The canvas to clear.
  222. * \return This function always returns 0.
  223. */
  224. int cucul_clear_canvas(cucul_canvas_t *cv)
  225. {
  226. uint32_t color = (cv->bgcolor << 16) | cv->fgcolor;
  227. unsigned int n;
  228. for(n = cv->width * cv->height; n--; )
  229. {
  230. cv->chars[n] = (uint32_t)' ';
  231. cv->attr[n] = color;
  232. }
  233. return 0;
  234. }
  235. /** \brief Blit a canvas onto another one.
  236. *
  237. * Blit a canvas onto another one at the given coordinates.
  238. * An optional mask canvas can be used.
  239. *
  240. * If an error occurs, -1 is returned and \b errno is set accordingly:
  241. * - \c EINVAL A mask was specified but the mask size and source canvas
  242. * size do not match.
  243. *
  244. * \param dst The destination canvas.
  245. * \param x X coordinate.
  246. * \param y Y coordinate.
  247. * \param src The source canvas.
  248. * \param mask The mask canvas.
  249. * \return 0 in case of success, -1 if an error occurred.
  250. */
  251. int cucul_blit(cucul_canvas_t *dst, int x, int y,
  252. cucul_canvas_t const *src, cucul_canvas_t const *mask)
  253. {
  254. int i, j, starti, startj, endi, endj;
  255. if(mask && (src->width != mask->width || src->height != mask->height))
  256. {
  257. #if defined(HAVE_ERRNO_H)
  258. errno = EINVAL;
  259. #endif
  260. return -1;
  261. }
  262. starti = x < 0 ? -x : 0;
  263. startj = y < 0 ? -y : 0;
  264. endi = (x + src->width >= dst->width) ? dst->width - x : src->width;
  265. endj = (y + src->height >= dst->height) ? dst->height - y : src->height;
  266. if((unsigned int)starti > src->width || (unsigned int)startj > src->height
  267. || starti >= endi || startj >= endj)
  268. return 0;
  269. for(j = startj; j < endj; j++)
  270. {
  271. unsigned int dstix = (j + y) * dst->width + starti + x;
  272. unsigned int srcix = j * src->width + starti;
  273. int stride = endi - starti;
  274. /* FIXME: we are ignoring the mask here */
  275. if((starti + x) && dst->chars[dstix] == CUCUL_MAGIC_FULLWIDTH)
  276. dst->chars[dstix - 1] = ' ';
  277. if((unsigned int)(endi + x) < dst->width
  278. && dst->chars[dstix + stride] == CUCUL_MAGIC_FULLWIDTH)
  279. dst->chars[dstix + stride] = ' ';
  280. if(mask)
  281. {
  282. for(i = 0; i < stride; i++)
  283. {
  284. if(mask->chars[srcix + i] == (uint32_t)' ')
  285. continue;
  286. dst->chars[dstix + i] = src->chars[srcix + i];
  287. dst->attr[dstix + i] = src->attr[srcix + i];
  288. }
  289. }
  290. else
  291. {
  292. memcpy(dst->chars + dstix, src->chars + srcix, (stride) * 4);
  293. memcpy(dst->attr + dstix, src->attr + srcix, (stride) * 4);
  294. }
  295. /* Fix split fullwidth chars */
  296. if(src->chars[srcix] == CUCUL_MAGIC_FULLWIDTH)
  297. dst->chars[dstix] = ' ';
  298. if((unsigned int)endi < src->width
  299. && src->chars[endi] == CUCUL_MAGIC_FULLWIDTH)
  300. dst->chars[dstix + stride - 1] = ' ';
  301. }
  302. return 0;
  303. }
  304. /** \brief Set a canvas' new boundaries.
  305. *
  306. * Set new boundaries for a canvas. This function can be used to crop a
  307. * canvas, to expand it or for combinations of both actions.
  308. *
  309. * If an error occurs, -1 is returned and \b errno is set accordingly:
  310. * - \c EBUSY The canvas is in use by a display driver and cannot be resized.
  311. * - \c ENOMEM Not enough memory for the requested canvas size. If this
  312. * happens, the canvas handle becomes invalid and should not be used.
  313. *
  314. * \param cv The canvas to crop.
  315. * \param x X coordinate of the top-left corner.
  316. * \param y Y coordinate of the top-left corner.
  317. * \param w The width of the cropped area.
  318. * \param h The height of the cropped area.
  319. * \return 0 in case of success, -1 if an error occurred.
  320. */
  321. int cucul_set_canvas_boundaries(cucul_canvas_t *cv, int x, int y,
  322. unsigned int w, unsigned int h)
  323. {
  324. cucul_canvas_t *new;
  325. unsigned int f, saved_f, framecount;
  326. if(cv->refcount)
  327. {
  328. #if defined(HAVE_ERRNO_H)
  329. errno = EBUSY;
  330. #endif
  331. return -1;
  332. }
  333. new = cucul_create_canvas(w, h);
  334. framecount = cucul_get_canvas_frame_count(cv);
  335. saved_f = cv->frame;
  336. for(f = 0; f < framecount; f++)
  337. {
  338. if(f)
  339. cucul_create_canvas_frame(new, framecount);
  340. cucul_set_canvas_frame(cv, f);
  341. cucul_set_canvas_frame(new, f);
  342. cucul_blit(new, -x, -y, cv, NULL);
  343. free(cv->allchars[f]);
  344. free(cv->allattr[f]);
  345. }
  346. free(cv->allchars);
  347. free(cv->allattr);
  348. memcpy(cv, new, sizeof(cucul_canvas_t));
  349. free(new);
  350. cucul_set_canvas_frame(cv, saved_f);
  351. return 0;
  352. }