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