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