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 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  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 functions for attribute management and colourspace
  15. * conversions.
  16. */
  17. #include "config.h"
  18. #include "common.h"
  19. #if defined(HAVE_ERRNO_H)
  20. # include <errno.h>
  21. #endif
  22. #include "cucul.h"
  23. #include "cucul_internals.h"
  24. static uint8_t nearest_ansi(uint16_t);
  25. /** \brief Get the text attribute at the given coordinates.
  26. *
  27. * Get the internal \e libcucul attribute value of the character at the
  28. * given coordinates. The attribute value has 32 significant bits,
  29. * organised as follows from MSB to LSB:
  30. * - 3 bits for the background alpha
  31. * - 4 bits for the background red component
  32. * - 4 bits for the background green component
  33. * - 3 bits for the background blue component
  34. * - 3 bits for the foreground alpha
  35. * - 4 bits for the foreground red component
  36. * - 4 bits for the foreground green component
  37. * - 3 bits for the foreground blue component
  38. * - 4 bits for the bold, italics, underline and blink flags
  39. *
  40. * If the coordinates are outside the canvas boundaries, the current
  41. * attribute is returned.
  42. *
  43. * This function never fails.
  44. *
  45. * \param cv A handle to the libcucul canvas.
  46. * \param x X coordinate.
  47. * \param y Y coordinate.
  48. * \return The requested attribute.
  49. */
  50. unsigned long int cucul_get_attr(cucul_canvas_t *cv, int x, int y)
  51. {
  52. if(x < 0 || x >= (int)cv->width || y < 0 || y >= (int)cv->height)
  53. return (unsigned long int)cv->curattr;
  54. return (unsigned long int)cv->attrs[x + y * cv->width];
  55. }
  56. /** \brief Set the default character attribute.
  57. *
  58. * Set the default character attribute for drawing. Attributes define
  59. * foreground and background colour, transparency, bold, italics and
  60. * underline styles, as well as blink. String functions such as
  61. * caca_printf() and graphical primitive functions such as caca_draw_line()
  62. * will use this attribute.
  63. *
  64. * The value of \e attr is either:
  65. * - a 32-bit integer as returned by cucul_get_attr(), in which case it
  66. * also contains colour information,
  67. * - a combination (bitwise OR) of style values (\e CUCUL_UNDERLINE,
  68. * \e CUCUL_BLINK, \e CUCUL_BOLD and \e CUCUL_ITALICS), in which case
  69. * setting the attribute does not modify the current colour information.
  70. *
  71. * To retrieve the current attribute value, use cucul_get_attr(-1,-1).
  72. *
  73. * If an error occurs, -1 is returned and \b errno is set accordingly:
  74. * - \c EINVAL The attribute value is out of the 32-bit range.
  75. *
  76. * \param cv A handle to the libcucul canvas.
  77. * \param attr The requested attribute value.
  78. * \return 0 in case of success, -1 if an error occurred.
  79. */
  80. int cucul_set_attr(cucul_canvas_t *cv, unsigned long int attr)
  81. {
  82. if(sizeof(unsigned long int) > sizeof(uint32_t) && attr > 0xffffffff)
  83. {
  84. #if defined(HAVE_ERRNO_H)
  85. errno = EINVAL;
  86. #endif
  87. return -1;
  88. }
  89. if(attr < 0x00000010)
  90. attr = (cv->curattr & 0xfffffff0) | attr;
  91. cv->curattr = attr;
  92. return 0;
  93. }
  94. /** \brief Set the character attribute at the given coordinates.
  95. *
  96. * Set the character attribute, without changing the character's value. If
  97. * the character at the given coordinates is a fullwidth character, both
  98. * cells' attributes are replaced.
  99. *
  100. * The value of \e attr is either:
  101. * - a 32-bit integer as returned by cucul_get_attr(), in which case it
  102. * also contains colour information,
  103. * - a combination (bitwise OR) of style values (\e CUCUL_UNDERLINE,
  104. * \e CUCUL_BLINK, \e CUCUL_BOLD and \e CUCUL_ITALICS), in which case
  105. * setting the attribute does not modify the current colour information.
  106. *
  107. * If an error occurs, -1 is returned and \b errno is set accordingly:
  108. * - \c EINVAL The attribute value is out of the 32-bit range.
  109. *
  110. * \param cv A handle to the libcucul canvas.
  111. * \param x X coordinate.
  112. * \param y Y coordinate.
  113. * \param attr The requested attribute value.
  114. * \return 0 in case of success, -1 if an error occurred.
  115. */
  116. int cucul_put_attr(cucul_canvas_t *cv, int x, int y, unsigned long int attr)
  117. {
  118. uint32_t *curattr, *curchar;
  119. if(sizeof(unsigned long int) > sizeof(uint32_t) && attr > 0xffffffff)
  120. {
  121. #if defined(HAVE_ERRNO_H)
  122. errno = EINVAL;
  123. #endif
  124. return -1;
  125. }
  126. if(x < 0 || x >= (int)cv->width || y < 0 || y >= (int)cv->height)
  127. return 0;
  128. curchar = cv->chars + x + y * cv->width;
  129. curattr = cv->attrs + x + y * cv->width;
  130. if(curattr[0] < 0x00000010)
  131. curattr[0] = (cv->curattr & 0xfffffff0) | curattr[0];
  132. if(x && curchar[0] == CUCUL_MAGIC_FULLWIDTH)
  133. curattr[-1] = curattr[0];
  134. else if(x + 1 < (int)cv->width && curchar[1] == CUCUL_MAGIC_FULLWIDTH)
  135. curattr[1] = curattr[0];
  136. return 0;
  137. }
  138. /** \brief Set the default colour pair for text (ANSI version).
  139. *
  140. * Set the default ANSI colour pair for text drawing. String functions such
  141. * as caca_printf() and graphical primitive functions such as caca_draw_line()
  142. * will use these attributes.
  143. *
  144. * Color values are those defined in cucul.h, such as CUCUL_RED
  145. * or CUCUL_TRANSPARENT.
  146. *
  147. * If an error occurs, 0 is returned and \b errno is set accordingly:
  148. * - \c EINVAL At least one of the colour values is invalid.
  149. *
  150. * \param cv A handle to the libcucul canvas.
  151. * \param fg The requested ANSI foreground colour.
  152. * \param bg The requested ANSI background colour.
  153. * \return 0 in case of success, -1 if an error occurred.
  154. */
  155. int cucul_set_color_ansi(cucul_canvas_t *cv, unsigned char fg, unsigned char bg)
  156. {
  157. uint32_t attr;
  158. if(fg > 0x20 || bg > 0x20)
  159. {
  160. #if defined(HAVE_ERRNO_H)
  161. errno = EINVAL;
  162. #endif
  163. return -1;
  164. }
  165. attr = ((uint32_t)(bg | 0x40) << 18) | ((uint32_t)(fg | 0x40) << 4);
  166. cv->curattr = (cv->curattr & 0x0000000f) | attr;
  167. return 0;
  168. }
  169. /** \brief Set the default colour pair for text (truecolor version).
  170. *
  171. * Set the default ARGB colour pair for text drawing. String functions such
  172. * as caca_printf() and graphical primitive functions such as caca_draw_line()
  173. * will use these attributes.
  174. *
  175. * Colors are 16-bit ARGB values, each component being coded on 4 bits. For
  176. * instance, 0xf088 is solid dark cyan (A=15 R=0 G=8 B=8), and 0x8fff is
  177. * white with 50% alpha (A=8 R=15 G=15 B=15).
  178. *
  179. * If an error occurs, 0 is returned and \b errno is set accordingly:
  180. * - \c EINVAL At least one of the colour values is invalid.
  181. *
  182. * \param cv A handle to the libcucul canvas.
  183. * \param fg The requested ARGB foreground colour.
  184. * \param bg The requested ARGB background colour.
  185. * \return 0 in case of success, -1 if an error occurred.
  186. */
  187. int cucul_set_color_argb(cucul_canvas_t *cv, unsigned int fg, unsigned int bg)
  188. {
  189. uint32_t attr;
  190. if(fg > 0xffff || bg > 0xffff)
  191. {
  192. #if defined(HAVE_ERRNO_H)
  193. errno = EINVAL;
  194. #endif
  195. return -1;
  196. }
  197. if(fg < 0x100)
  198. fg += 0x100;
  199. if(bg < 0x100)
  200. bg += 0x100;
  201. fg = ((fg >> 1) & 0x7ff) | ((fg >> 13) << 11);
  202. bg = ((bg >> 1) & 0x7ff) | ((bg >> 13) << 11);
  203. attr = ((uint32_t)bg << 18) | ((uint32_t)fg << 4);
  204. cv->curattr = (cv->curattr & 0x0000000f) | attr;
  205. return 0;
  206. }
  207. /** \brief Get DOS ANSI information from attribute.
  208. *
  209. * Get the ANSI colour pair for a given attribute. The returned value is
  210. * an 8-bit value whose higher 4 bits are the background colour and lower
  211. * 4 bits are the foreground colour.
  212. *
  213. * If the attribute has ARGB colours, the nearest colour is used. Special
  214. * attributes such as \e CUCUL_DEFAULT and \e CUCUL_TRANSPARENT are not
  215. * handled and are both replaced with \e CUCUL_LIGHTGRAY for the foreground
  216. * colour and \e CUCUL_BLACK for the background colour.
  217. *
  218. * This function never fails. If the attribute value is outside the expected
  219. * 32-bit range, higher order bits are simply ignored.
  220. *
  221. * \param attr The requested attribute value.
  222. * \return The corresponding DOS ANSI value.
  223. */
  224. unsigned char cucul_attr_to_ansi(unsigned long int attr)
  225. {
  226. uint8_t fg = nearest_ansi((attr >> 4) & 0x3fff);
  227. uint8_t bg = nearest_ansi(attr >> 18);
  228. return (fg < 0x10 ? fg : CUCUL_LIGHTGRAY)
  229. | ((bg < 0x10 ? bg : CUCUL_BLACK) << 4);
  230. }
  231. /** \brief Get ANSI foreground information from attribute.
  232. *
  233. * Get the ANSI foreground colour value for a given attribute. The returned
  234. * value is either one of the \e CUCUL_RED, \e CUCUL_BLACK etc. predefined
  235. * colours, or the special value \e CUCUL_DEFAULT meaning the media's
  236. * default foreground value, or the special value \e CUCUL_TRANSPARENT.
  237. *
  238. * If the attribute has ARGB colours, the nearest colour is returned.
  239. *
  240. * This function never fails. If the attribute value is outside the expected
  241. * 32-bit range, higher order bits are simply ignored.
  242. *
  243. * \param attr The requested attribute value.
  244. * \return The corresponding ANSI foreground value.
  245. */
  246. unsigned char cucul_attr_to_ansi_fg(unsigned long int attr)
  247. {
  248. return nearest_ansi(((uint16_t)attr >> 4) & 0x3fff);
  249. }
  250. /** \brief Get ANSI background information from attribute.
  251. *
  252. * Get the ANSI background colour value for a given attribute. The returned
  253. * value is either one of the \e CUCUL_RED, \e CUCUL_BLACK etc. predefined
  254. * colours, or the special value \e CUCUL_DEFAULT meaning the media's
  255. * default background value, or the special value \e CUCUL_TRANSPARENT.
  256. *
  257. * If the attribute has ARGB colours, the nearest colour is returned.
  258. *
  259. * This function never fails. If the attribute value is outside the expected
  260. * 32-bit range, higher order bits are simply ignored.
  261. *
  262. * \param attr The requested attribute value.
  263. * \return The corresponding ANSI background value.
  264. */
  265. unsigned char cucul_attr_to_ansi_bg(unsigned long int attr)
  266. {
  267. return nearest_ansi(attr >> 18);
  268. }
  269. /*
  270. * XXX: the following functions are local
  271. */
  272. /* RGB colours for the ANSI palette. There is no real standard, so we
  273. * use the same values as gnome-terminal. The 7th colour (brown) is a bit
  274. * special: 0xfa50 instead of 0xfaa0. */
  275. static const uint16_t ansitab16[16] =
  276. {
  277. 0xf000, 0xf00a, 0xf0a0, 0xf0aa, 0xfa00, 0xfa0a, 0xfa50, 0xfaaa,
  278. 0xf555, 0xf55f, 0xf5f5, 0xf5ff, 0xff55, 0xff5f, 0xfff5, 0xffff,
  279. };
  280. /* Same table, except on 14 bits (3-4-4-3) */
  281. static const uint16_t ansitab14[16] =
  282. {
  283. 0x3800, 0x3805, 0x3850, 0x3855, 0x3d00, 0x3d05, 0x3d28, 0x3d55,
  284. 0x3aaa, 0x3aaf, 0x3afa, 0x3aff, 0x3faa, 0x3faf, 0x3ffa, 0x3fff,
  285. };
  286. static uint8_t nearest_ansi(uint16_t argb14)
  287. {
  288. unsigned int i, best, dist;
  289. if(argb14 < (0x10 | 0x40))
  290. return argb14 ^ 0x40;
  291. if(argb14 == (CUCUL_DEFAULT | 0x40) || argb14 == (CUCUL_TRANSPARENT | 0x40))
  292. return argb14 ^ 0x40;
  293. if(argb14 < 0x0fff) /* too transparent */
  294. return CUCUL_TRANSPARENT;
  295. best = CUCUL_DEFAULT;
  296. dist = 0x3fff;
  297. for(i = 0; i < 16; i++)
  298. {
  299. unsigned int d = 0;
  300. int a, b;
  301. a = (ansitab14[i] >> 7) & 0xf;
  302. b = (argb14 >> 7) & 0xf;
  303. d += (a - b) * (a - b);
  304. a = (ansitab14[i] >> 3) & 0xf;
  305. b = (argb14 >> 3) & 0xf;
  306. d += (a - b) * (a - b);
  307. a = (ansitab14[i] << 1) & 0xf;
  308. b = (argb14 << 1) & 0xf;
  309. d += (a - b) * (a - b);
  310. if(d < dist)
  311. {
  312. dist = d;
  313. best = i;
  314. }
  315. }
  316. return best;
  317. }
  318. uint16_t _cucul_attr_to_rgb12fg(uint32_t attr)
  319. {
  320. uint16_t fg = (attr >> 4) & 0x3fff;
  321. if(fg < (0x10 | 0x40))
  322. return ansitab16[fg ^ 0x40] & 0x0fff;
  323. if(fg == (CUCUL_DEFAULT | 0x40))
  324. return ansitab16[CUCUL_LIGHTGRAY] & 0x0fff;
  325. if(fg == (CUCUL_TRANSPARENT | 0x40))
  326. return ansitab16[CUCUL_LIGHTGRAY] & 0x0fff;
  327. return (fg << 1) & 0x0fff;
  328. }
  329. uint16_t _cucul_attr_to_rgb12bg(uint32_t attr)
  330. {
  331. uint16_t bg = attr >> 18;
  332. if(bg < (0x10 | 0x40))
  333. return ansitab16[bg ^ 0x40] & 0x0fff;
  334. if(bg == (CUCUL_DEFAULT | 0x40))
  335. return ansitab16[CUCUL_BLACK] & 0x0fff;
  336. if(bg == (CUCUL_TRANSPARENT | 0x40))
  337. return ansitab16[CUCUL_BLACK] & 0x0fff;
  338. return (bg << 1) & 0x0fff;
  339. }
  340. #define RGB12TO24(i) \
  341. (((uint32_t)((i & 0xf00) >> 8) * 0x110000) \
  342. | ((uint32_t)((i & 0x0f0) >> 4) * 0x001100) \
  343. | ((uint32_t)(i & 0x00f) * 0x000011))
  344. uint32_t _cucul_attr_to_rgb24fg(uint32_t attr)
  345. {
  346. return RGB12TO24(_cucul_attr_to_rgb12fg(attr));
  347. }
  348. uint32_t _cucul_attr_to_rgb24bg(uint32_t attr)
  349. {
  350. return RGB12TO24(_cucul_attr_to_rgb12bg(attr));
  351. }
  352. void _cucul_attr_to_argb4(uint32_t attr, uint8_t argb[8])
  353. {
  354. uint16_t fg = (attr >> 4) & 0x3fff;
  355. uint16_t bg = attr >> 18;
  356. if(bg < (0x10 | 0x40))
  357. bg = ansitab16[bg ^ 0x40];
  358. else if(bg == (CUCUL_DEFAULT | 0x40))
  359. bg = ansitab16[CUCUL_BLACK];
  360. else if(bg == (CUCUL_TRANSPARENT | 0x40))
  361. bg = 0x0fff;
  362. else
  363. bg = ((bg << 2) & 0xf000) | ((bg << 1) & 0x0fff);
  364. argb[0] = bg >> 12;
  365. argb[1] = (bg >> 8) & 0xf;
  366. argb[2] = (bg >> 4) & 0xf;
  367. argb[3] = bg & 0xf;
  368. if(fg < (0x10 | 0x40))
  369. fg = ansitab16[fg ^ 0x40];
  370. else if(fg == (CUCUL_DEFAULT | 0x40))
  371. fg = ansitab16[CUCUL_LIGHTGRAY];
  372. else if(fg == (CUCUL_TRANSPARENT | 0x40))
  373. fg = 0x0fff;
  374. else
  375. fg = ((fg << 2) & 0xf000) | ((fg << 1) & 0x0fff);
  376. argb[4] = fg >> 12;
  377. argb[5] = (fg >> 8) & 0xf;
  378. argb[6] = (fg >> 4) & 0xf;
  379. argb[7] = fg & 0xf;
  380. }