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