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.

attr.c 14 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  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. uint32_t 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 cv->curattr;
  65. return 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. * This function never fails.
  85. *
  86. * \param cv A handle to the libcucul canvas.
  87. * \param attr The requested attribute value.
  88. * \return This function always returns 0.
  89. */
  90. int cucul_set_attr(cucul_canvas_t *cv, uint32_t attr)
  91. {
  92. if(attr < 0x00000010)
  93. attr = (cv->curattr & 0xfffffff0) | attr;
  94. cv->curattr = attr;
  95. return 0;
  96. }
  97. /** \brief Set the character attribute at the given coordinates.
  98. *
  99. * Set the character attribute, without changing the character's value. If
  100. * the character at the given coordinates is a fullwidth character, both
  101. * cells' attributes are replaced.
  102. *
  103. * The value of \e attr is either:
  104. * - a 32-bit integer as returned by cucul_get_attr(), in which case it
  105. * also contains colour information,
  106. * - a combination (bitwise OR) of style values (\e CUCUL_UNDERLINE,
  107. * \e CUCUL_BLINK, \e CUCUL_BOLD and \e CUCUL_ITALICS), in which case
  108. * setting the attribute does not modify the current colour information.
  109. *
  110. * This function never fails.
  111. *
  112. * \param cv A handle to the libcucul canvas.
  113. * \param x X coordinate.
  114. * \param y Y coordinate.
  115. * \param attr The requested attribute value.
  116. * \return This function always returns 0.
  117. */
  118. int cucul_put_attr(cucul_canvas_t *cv, int x, int y, uint32_t attr)
  119. {
  120. uint32_t *curattr, *curchar;
  121. if(x < 0 || x >= (int)cv->width || y < 0 || y >= (int)cv->height)
  122. return 0;
  123. curchar = cv->chars + x + y * cv->width;
  124. curattr = cv->attrs + x + y * cv->width;
  125. if(attr < 0x00000010)
  126. curattr[0] = (curattr[0] & 0xfffffff0) | attr;
  127. else
  128. curattr[0] = attr;
  129. if(x && curchar[0] == CUCUL_MAGIC_FULLWIDTH)
  130. curattr[-1] = curattr[0];
  131. else if(x + 1 < (int)cv->width && curchar[1] == CUCUL_MAGIC_FULLWIDTH)
  132. curattr[1] = curattr[0];
  133. return 0;
  134. }
  135. /** \brief Set the default colour pair for text (ANSI version).
  136. *
  137. * Set the default ANSI colour pair for text drawing. String functions such
  138. * as caca_printf() and graphical primitive functions such as caca_draw_line()
  139. * will use these attributes.
  140. *
  141. * Color values are those defined in cucul.h, such as CUCUL_RED
  142. * or CUCUL_TRANSPARENT.
  143. *
  144. * If an error occurs, 0 is returned and \b errno is set accordingly:
  145. * - \c EINVAL At least one of the colour values is invalid.
  146. *
  147. * \param cv A handle to the libcucul canvas.
  148. * \param fg The requested ANSI foreground colour.
  149. * \param bg The requested ANSI background colour.
  150. * \return 0 in case of success, -1 if an error occurred.
  151. */
  152. int cucul_set_color_ansi(cucul_canvas_t *cv, uint8_t fg, uint8_t bg)
  153. {
  154. uint32_t attr;
  155. if(fg > 0x20 || bg > 0x20)
  156. {
  157. seterrno(EINVAL);
  158. return -1;
  159. }
  160. attr = ((uint32_t)(bg | 0x40) << 18) | ((uint32_t)(fg | 0x40) << 4);
  161. cv->curattr = (cv->curattr & 0x0000000f) | attr;
  162. return 0;
  163. }
  164. /** \brief Set the default colour pair for text (truecolor version).
  165. *
  166. * Set the default ARGB colour pair for text drawing. String functions such
  167. * as caca_printf() and graphical primitive functions such as caca_draw_line()
  168. * will use these attributes.
  169. *
  170. * Colors are 16-bit ARGB values, each component being coded on 4 bits. For
  171. * instance, 0xf088 is solid dark cyan (A=15 R=0 G=8 B=8), and 0x8fff is
  172. * white with 50% alpha (A=8 R=15 G=15 B=15).
  173. *
  174. * This function never fails.
  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 This function always returns 0.
  180. */
  181. int cucul_set_color_argb(cucul_canvas_t *cv, uint16_t fg, uint16_t bg)
  182. {
  183. uint32_t attr;
  184. if(fg < 0x100)
  185. fg += 0x100;
  186. if(bg < 0x100)
  187. bg += 0x100;
  188. fg = ((fg >> 1) & 0x7ff) | ((fg >> 13) << 11);
  189. bg = ((bg >> 1) & 0x7ff) | ((bg >> 13) << 11);
  190. attr = ((uint32_t)bg << 18) | ((uint32_t)fg << 4);
  191. cv->curattr = (cv->curattr & 0x0000000f) | attr;
  192. return 0;
  193. }
  194. /** \brief Get DOS ANSI information from attribute.
  195. *
  196. * Get the ANSI colour pair for a given attribute. The returned value is
  197. * an 8-bit value whose higher 4 bits are the background colour and lower
  198. * 4 bits are the foreground colour.
  199. *
  200. * If the attribute has ARGB colours, the nearest colour is used. Special
  201. * attributes such as \e CUCUL_DEFAULT and \e CUCUL_TRANSPARENT are not
  202. * handled and are both replaced with \e CUCUL_LIGHTGRAY for the foreground
  203. * colour and \e CUCUL_BLACK for the background colour.
  204. *
  205. * This function never fails. If the attribute value is outside the expected
  206. * 32-bit range, higher order bits are simply ignored.
  207. *
  208. * \param attr The requested attribute value.
  209. * \return The corresponding DOS ANSI value.
  210. */
  211. uint8_t cucul_attr_to_ansi(uint32_t attr)
  212. {
  213. uint8_t fg = nearest_ansi((attr >> 4) & 0x3fff);
  214. uint8_t bg = nearest_ansi(attr >> 18);
  215. return (fg < 0x10 ? fg : CUCUL_LIGHTGRAY)
  216. | ((bg < 0x10 ? bg : CUCUL_BLACK) << 4);
  217. }
  218. /** \brief Get ANSI foreground information from attribute.
  219. *
  220. * Get the ANSI foreground colour value for a given attribute. The returned
  221. * value is either one of the \e CUCUL_RED, \e CUCUL_BLACK etc. predefined
  222. * colours, or the special value \e CUCUL_DEFAULT meaning the media's
  223. * default foreground value, or the special value \e CUCUL_TRANSPARENT.
  224. *
  225. * If the attribute has ARGB colours, the nearest colour is returned.
  226. *
  227. * This function never fails. If the attribute value is outside the expected
  228. * 32-bit range, higher order bits are simply ignored.
  229. *
  230. * \param attr The requested attribute value.
  231. * \return The corresponding ANSI foreground value.
  232. */
  233. uint8_t cucul_attr_to_ansi_fg(uint32_t attr)
  234. {
  235. return nearest_ansi(((uint16_t)attr >> 4) & 0x3fff);
  236. }
  237. /** \brief Get ANSI background information from attribute.
  238. *
  239. * Get the ANSI background 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 background 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 background value.
  251. */
  252. uint8_t cucul_attr_to_ansi_bg(uint32_t attr)
  253. {
  254. return nearest_ansi(attr >> 18);
  255. }
  256. /** \brief Get 12-bit RGB foreground information from attribute.
  257. *
  258. * Get the 12-bit foreground colour value for a given attribute. The returned
  259. * value is a native-endian encoded integer with each red, green and blue
  260. * values encoded on 8 bits in the following order:
  261. * - 8-11 most significant bits: red
  262. * - 4-7 most significant bits: green
  263. * - least significant bits: blue
  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 12-bit RGB foreground value.
  270. */
  271. uint16_t cucul_attr_to_rgb12_fg(uint32_t attr)
  272. {
  273. uint16_t fg = (attr >> 4) & 0x3fff;
  274. if(fg < (0x10 | 0x40))
  275. return ansitab16[fg ^ 0x40] & 0x0fff;
  276. if(fg == (CUCUL_DEFAULT | 0x40))
  277. return ansitab16[CUCUL_LIGHTGRAY] & 0x0fff;
  278. if(fg == (CUCUL_TRANSPARENT | 0x40))
  279. return ansitab16[CUCUL_LIGHTGRAY] & 0x0fff;
  280. return (fg << 1) & 0x0fff;
  281. }
  282. /** \brief Get 12-bit RGB background information from attribute.
  283. *
  284. * Get the 12-bit background colour value for a given attribute. The returned
  285. * value is a native-endian encoded integer with each red, green and blue
  286. * values encoded on 8 bits in the following order:
  287. * - 8-11 most significant bits: red
  288. * - 4-7 most significant bits: green
  289. * - least significant bits: blue
  290. *
  291. * This function never fails. If the attribute value is outside the expected
  292. * 32-bit range, higher order bits are simply ignored.
  293. *
  294. * \param attr The requested attribute value.
  295. * \return The corresponding 12-bit RGB background value.
  296. */
  297. uint16_t cucul_attr_to_rgb12_bg(uint32_t attr)
  298. {
  299. uint16_t bg = attr >> 18;
  300. if(bg < (0x10 | 0x40))
  301. return ansitab16[bg ^ 0x40] & 0x0fff;
  302. if(bg == (CUCUL_DEFAULT | 0x40))
  303. return ansitab16[CUCUL_BLACK] & 0x0fff;
  304. if(bg == (CUCUL_TRANSPARENT | 0x40))
  305. return ansitab16[CUCUL_BLACK] & 0x0fff;
  306. return (bg << 1) & 0x0fff;
  307. }
  308. /** \brief Get 64-bit ARGB information from attribute.
  309. *
  310. * Get the 64-bit colour and alpha values for a given attribute. The values
  311. * are written as 8-bit integers in the \e argb array in the following order:
  312. * - \e argb[0]: background alpha value
  313. * - \e argb[1]: background red value
  314. * - \e argb[2]: background green value
  315. * - \e argb[3]: background blue value
  316. * - \e argb[4]: foreground alpha value
  317. * - \e argb[5]: foreground red value
  318. * - \e argb[6]: foreground green value
  319. * - \e argb[7]: foreground blue value
  320. *
  321. * This function never fails. If the attribute value is outside the expected
  322. * 32-bit range, higher order bits are simply ignored.
  323. *
  324. * \param attr The requested attribute value.
  325. * \param argb An array of 8-bit integers.
  326. */
  327. void cucul_attr_to_argb64(uint32_t attr, uint8_t argb[8])
  328. {
  329. uint16_t fg = (attr >> 4) & 0x3fff;
  330. uint16_t bg = attr >> 18;
  331. if(bg < (0x10 | 0x40))
  332. bg = ansitab16[bg ^ 0x40];
  333. else if(bg == (CUCUL_DEFAULT | 0x40))
  334. bg = ansitab16[CUCUL_BLACK];
  335. else if(bg == (CUCUL_TRANSPARENT | 0x40))
  336. bg = 0x0fff;
  337. else
  338. bg = ((bg << 2) & 0xf000) | ((bg << 1) & 0x0fff);
  339. argb[0] = bg >> 12;
  340. argb[1] = (bg >> 8) & 0xf;
  341. argb[2] = (bg >> 4) & 0xf;
  342. argb[3] = bg & 0xf;
  343. if(fg < (0x10 | 0x40))
  344. fg = ansitab16[fg ^ 0x40];
  345. else if(fg == (CUCUL_DEFAULT | 0x40))
  346. fg = ansitab16[CUCUL_LIGHTGRAY];
  347. else if(fg == (CUCUL_TRANSPARENT | 0x40))
  348. fg = 0x0fff;
  349. else
  350. fg = ((fg << 2) & 0xf000) | ((fg << 1) & 0x0fff);
  351. argb[4] = fg >> 12;
  352. argb[5] = (fg >> 8) & 0xf;
  353. argb[6] = (fg >> 4) & 0xf;
  354. argb[7] = fg & 0xf;
  355. }
  356. /*
  357. * XXX: the following functions are local
  358. */
  359. static uint8_t nearest_ansi(uint16_t argb14)
  360. {
  361. unsigned int i, best, dist;
  362. if(argb14 < (0x10 | 0x40))
  363. return argb14 ^ 0x40;
  364. if(argb14 == (CUCUL_DEFAULT | 0x40) || argb14 == (CUCUL_TRANSPARENT | 0x40))
  365. return argb14 ^ 0x40;
  366. if(argb14 < 0x0fff) /* too transparent */
  367. return CUCUL_TRANSPARENT;
  368. best = CUCUL_DEFAULT;
  369. dist = 0x3fff;
  370. for(i = 0; i < 16; i++)
  371. {
  372. unsigned int d = 0;
  373. int a, b;
  374. a = (ansitab14[i] >> 7) & 0xf;
  375. b = (argb14 >> 7) & 0xf;
  376. d += (a - b) * (a - b);
  377. a = (ansitab14[i] >> 3) & 0xf;
  378. b = (argb14 >> 3) & 0xf;
  379. d += (a - b) * (a - b);
  380. a = (ansitab14[i] << 1) & 0xf;
  381. b = (argb14 << 1) & 0xf;
  382. d += (a - b) * (a - b);
  383. if(d < dist)
  384. {
  385. dist = d;
  386. best = i;
  387. }
  388. }
  389. return best;
  390. }
  391. #define RGB12TO24(i) \
  392. (((uint32_t)((i & 0xf00) >> 8) * 0x110000) \
  393. | ((uint32_t)((i & 0x0f0) >> 4) * 0x001100) \
  394. | ((uint32_t)(i & 0x00f) * 0x000011))
  395. uint32_t _cucul_attr_to_rgb24fg(uint32_t attr)
  396. {
  397. return RGB12TO24(cucul_attr_to_rgb12_fg(attr));
  398. }
  399. uint32_t _cucul_attr_to_rgb24bg(uint32_t attr)
  400. {
  401. return RGB12TO24(cucul_attr_to_rgb12_bg(attr));
  402. }