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.
 
 
 
 
 
 

335 lines
9.7 KiB

  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 horizontal and vertical flipping routines.
  15. */
  16. #include "config.h"
  17. #if !defined(__KERNEL__)
  18. #endif
  19. #include "cucul.h"
  20. #include "cucul_internals.h"
  21. static uint32_t flipchar(uint32_t ch);
  22. static uint32_t flopchar(uint32_t ch);
  23. static uint32_t rotatechar(uint32_t ch);
  24. /** \brief Invert a canvas' colours.
  25. *
  26. * This function inverts a canvas' colours (black becomes white, red
  27. * becomes cyan, etc.) without changing the characters in it.
  28. *
  29. * \param qq The canvas to invert.
  30. */
  31. void cucul_invert(cucul_t *qq)
  32. {
  33. uint32_t *attr = qq->attr;
  34. unsigned int i;
  35. for(i = qq->height * qq->width; i--; )
  36. {
  37. *attr = *attr ^ 0x000f000f;
  38. attr++;
  39. }
  40. }
  41. /** \brief Flip a canvas horizontally.
  42. *
  43. * This function flips a canvas horizontally, choosing characters that
  44. * look like the mirrored version wherever possible.
  45. *
  46. * \param qq The canvas to flip.
  47. */
  48. void cucul_flip(cucul_t *qq)
  49. {
  50. unsigned int y;
  51. for(y = 0; y < qq->height; y++)
  52. {
  53. uint32_t *cleft = qq->chars + y * qq->width;
  54. uint32_t *cright = cleft + qq->width - 1;
  55. uint32_t *aleft = qq->attr + y * qq->width;
  56. uint32_t *aright = aleft + qq->width - 1;
  57. while(cleft < cright)
  58. {
  59. uint32_t ch;
  60. uint32_t attr;
  61. /* Swap attributes */
  62. attr = *aright; *aright = *aleft; *aleft = attr;
  63. /* Swap characters */
  64. ch = *cright; *cright = flipchar(*cleft); *cleft = flipchar(ch);
  65. cleft++; cright--; aleft++; aright--;
  66. }
  67. if(cleft == cright)
  68. *cleft = flipchar(*cleft);
  69. }
  70. }
  71. /** \brief Flip a canvas vertically.
  72. *
  73. * This function flips a canvas vertically, choosing characters that
  74. * look like the mirrored version wherever possible.
  75. *
  76. * \param qq The canvas to flop.
  77. */
  78. void cucul_flop(cucul_t *qq)
  79. {
  80. unsigned int x;
  81. for(x = 0; x < qq->width; x++)
  82. {
  83. uint32_t *ctop = qq->chars + x;
  84. uint32_t *cbottom = ctop + qq->width * (qq->height - 1);
  85. uint32_t *atop = qq->attr + x;
  86. uint32_t *abottom = atop + qq->width * (qq->height - 1);
  87. while(ctop < cbottom)
  88. {
  89. uint32_t ch;
  90. uint32_t attr;
  91. /* Swap attributes */
  92. attr = *abottom; *abottom = *atop; *atop = attr;
  93. /* Swap characters */
  94. ch = *cbottom; *cbottom = flopchar(*ctop); *ctop = flopchar(ch);
  95. ctop += qq->width; cbottom -= qq->width;
  96. atop += qq->width; abottom -= qq->width;
  97. }
  98. if(ctop == cbottom)
  99. *ctop = flopchar(*ctop);
  100. }
  101. }
  102. /** \brief Rotate a canvas.
  103. *
  104. * This function applies a 180 degrees transformation to a canvas,
  105. * choosing characters that look like the mirrored version wherever
  106. * possible.
  107. *
  108. * \param qq The canvas to rotate.
  109. */
  110. void cucul_rotate(cucul_t *qq)
  111. {
  112. uint32_t *cbegin = qq->chars;
  113. uint32_t *cend = cbegin + qq->width * qq->height - 1;
  114. uint32_t *abegin = qq->attr;
  115. uint32_t *aend = abegin + qq->width * qq->height - 1;
  116. while(cbegin < cend)
  117. {
  118. uint32_t ch;
  119. uint32_t attr;
  120. /* Swap attributes */
  121. attr = *aend; *aend = *abegin; *abegin = attr;
  122. /* Swap characters */
  123. ch = *cend; *cend = rotatechar(*cbegin); *cbegin = rotatechar(ch);
  124. cbegin++; cend--; abegin++; aend--;
  125. }
  126. if(cbegin == cend)
  127. *cbegin = rotatechar(*cbegin);
  128. }
  129. static uint32_t flipchar(uint32_t ch)
  130. {
  131. int i;
  132. static uint32_t const noflip[] =
  133. {
  134. /* ASCII */
  135. (uint32_t)' ', (uint32_t)'"', (uint32_t)'#', (uint32_t)'\'',
  136. (uint32_t)'-', (uint32_t)'.', (uint32_t)'*', (uint32_t)'+',
  137. (uint32_t)':', (uint32_t)'=',
  138. (uint32_t)'0', (uint32_t)'8', (uint32_t)'A', (uint32_t)'H',
  139. (uint32_t)'I', (uint32_t)'M', (uint32_t)'O', (uint32_t)'T',
  140. (uint32_t)'U', (uint32_t)'V', (uint32_t)'W', (uint32_t)'X',
  141. (uint32_t)'Y', (uint32_t)'^', (uint32_t)'_', (uint32_t)'i',
  142. (uint32_t)'o', (uint32_t)'v', (uint32_t)'w', (uint32_t)'x',
  143. (uint32_t)'|',
  144. /* Unicode */
  145. 0x2591, 0x2592, 0x2593, 0x2588, 0x2584, 0x2580, /* ░ ▒ ▓ █ ▄ ▀ */
  146. 0
  147. };
  148. static uint32_t const pairs[] =
  149. {
  150. /* ASCII */
  151. (uint32_t)'(', (uint32_t)')', (uint32_t)'/', (uint32_t)'\\',
  152. (uint32_t)'<', (uint32_t)'>', (uint32_t)'[', (uint32_t)']',
  153. (uint32_t)'b', (uint32_t)'d', (uint32_t)'p', (uint32_t)'q',
  154. (uint32_t)'{', (uint32_t)'}',
  155. /* ASCII-Unicode */
  156. (uint32_t)';', 0x204f, /* ; ⁏ */
  157. (uint32_t)'`', 0x00b4, /* ` ´ */
  158. (uint32_t)'E', 0x018e, /* E Ǝ */
  159. (uint32_t)'N', 0x0418, /* N И */
  160. (uint32_t)'R', 0x042f, /* R Я */
  161. (uint32_t)'S', 0x01a7, /* S Ƨ */
  162. (uint32_t)'c', 0x0254, /* c ɔ */
  163. (uint32_t)'e', 0x0258, /* e ɘ */
  164. /* Unicode only */
  165. 0x258c, 0x2590, /* ▌ ▐ */
  166. 0x2596, 0x2597, /* ▖ ▗ */
  167. 0x2598, 0x259d, /* ▘ ▝ */
  168. 0x2599, 0x259f, /* ▙ ▟ */
  169. 0x259a, 0x259e, /* ▚ ▞ */
  170. 0x259b, 0x259c, /* ▛ ▜ */
  171. 0
  172. };
  173. for(i = 0; noflip[i]; i++)
  174. if(ch == noflip[i])
  175. return ch;
  176. for(i = 0; pairs[i]; i++)
  177. if(ch == pairs[i])
  178. return pairs[i ^ 1];
  179. return ch;
  180. }
  181. static uint32_t flopchar(uint32_t ch)
  182. {
  183. int i;
  184. static uint32_t const noflop[] =
  185. {
  186. /* ASCII */
  187. (uint32_t)' ', (uint32_t)'(', (uint32_t)')', (uint32_t)'*',
  188. (uint32_t)'+', (uint32_t)'-',
  189. (uint32_t)'0', (uint32_t)'3', (uint32_t)'8', (uint32_t)':',
  190. (uint32_t)'<', (uint32_t)'=', (uint32_t)'>', (uint32_t)'B',
  191. (uint32_t)'C', (uint32_t)'D', (uint32_t)'E', (uint32_t)'H',
  192. (uint32_t)'I', (uint32_t)'K', (uint32_t)'O', (uint32_t)'X',
  193. (uint32_t)'[', (uint32_t)']', (uint32_t)'c', (uint32_t)'o',
  194. (uint32_t)'{', (uint32_t)'|', (uint32_t)'}',
  195. /* Unicode */
  196. 0x2591, 0x2592, 0x2593, 0x2588, 0x258c, 0x2590, /* ░ ▒ ▓ █ ▌ ▐ */
  197. 0
  198. };
  199. static uint32_t const pairs[] =
  200. {
  201. /* ASCII */
  202. (uint32_t)'/', (uint32_t)'\\', (uint32_t)'M', (uint32_t)'W',
  203. (uint32_t)',', (uint32_t)'`', (uint32_t)'b', (uint32_t)'p',
  204. (uint32_t)'d', (uint32_t)'q', (uint32_t)'p', (uint32_t)'q',
  205. (uint32_t)'f', (uint32_t)'t', (uint32_t)'.', (uint32_t)'\'',
  206. /* ASCII-Unicode */
  207. (uint32_t)'_', 0x2594, /* _ ▔ */
  208. (uint32_t)'`', 0x201a, /* ` ‚ */
  209. (uint32_t)'!', 0x00a1, /* ! ¡ */
  210. (uint32_t)'N', 0x0418, /* N И */
  211. (uint32_t)'P', 0x042c, /* P Ь */
  212. (uint32_t)'S', 0x01a7, /* S Ƨ */
  213. (uint32_t)'v', 0x028c, /* v ʌ */
  214. (uint32_t)'w', 0x028d, /* w ʍ */
  215. /* Unicode only */
  216. 0x2584, 0x2580, /* ▄ ▀ */
  217. 0x2596, 0x2598, /* ▖ ▘ */
  218. 0x2597, 0x259d, /* ▗ ▝ */
  219. 0x2599, 0x259b, /* ▙ ▛ */
  220. 0x259f, 0x259c, /* ▟ ▜ */
  221. 0x259a, 0x259e, /* ▚ ▞ */
  222. 0
  223. };
  224. for(i = 0; noflop[i]; i++)
  225. if(ch == noflop[i])
  226. return ch;
  227. for(i = 0; pairs[i]; i++)
  228. if(ch == pairs[i])
  229. return pairs[i ^ 1];
  230. return ch;
  231. }
  232. static uint32_t rotatechar(uint32_t ch)
  233. {
  234. int i;
  235. static uint32_t const norotate[] =
  236. {
  237. /* ASCII - FIXME: a lot are missing */
  238. (uint32_t)' ', (uint32_t)'*', (uint32_t)'+', (uint32_t)'-',
  239. (uint32_t)'0', (uint32_t)'8', (uint32_t)':', (uint32_t)'=',
  240. /* Unicode */
  241. 0x2591, 0x2592, 0x2593, 0x2588, 0x259a, 0x259e, /* ░ ▒ ▓ █ ▚ ▞ */
  242. 0
  243. };
  244. static uint32_t const pairs[] =
  245. {
  246. /* ASCII */
  247. (uint32_t)'(', (uint32_t)')', (uint32_t)'<', (uint32_t)'>',
  248. (uint32_t)'[', (uint32_t)']', (uint32_t)'{', (uint32_t)'}',
  249. (uint32_t)'.', (uint32_t)'\'',
  250. (uint32_t)'6', (uint32_t)'9',
  251. (uint32_t)'M', (uint32_t)'W', (uint32_t)'b', (uint32_t)'q',
  252. (uint32_t)'d', (uint32_t)'p', (uint32_t)'n', (uint32_t)'u',
  253. /* ASCII-Unicode */
  254. (uint32_t)'_', 0x2594, /* _ ▔ */
  255. (uint32_t)',', 0x02bb, /* , ʻ */
  256. (uint32_t)'!', 0x00a1, /* ! ¡ */
  257. (uint32_t)'?', 0x00bf, /* ? ¿ */
  258. (uint32_t)'E', 0x018e, /* E Ǝ */
  259. (uint32_t)'F', 0x2132, /* F Ⅎ */
  260. (uint32_t)'a', 0x0250, /* a ɐ */
  261. (uint32_t)'c', 0x0254, /* c ɔ */
  262. (uint32_t)'e', 0x0259, /* e ə */
  263. (uint32_t)'f', 0x025f, /* f ɟ */
  264. (uint32_t)'h', 0x0265, /* h ɥ */
  265. (uint32_t)'k', 0x029e, /* k ʞ */
  266. (uint32_t)'m', 0x026f, /* m ɯ */
  267. (uint32_t)'r', 0x0279, /* r ɹ */
  268. (uint32_t)'t', 0x0287, /* t ʇ */
  269. (uint32_t)'v', 0x028c, /* v ʌ */
  270. (uint32_t)'w', 0x028d, /* w ʍ */
  271. (uint32_t)'y', 0x028e, /* y ʎ */
  272. /* Unicode only */
  273. 0x258c, 0x2590, /* ▌ ▐ */
  274. 0x2584, 0x2580, /* ▄ ▀ */
  275. 0x2596, 0x259d, /* ▖ ▝ */
  276. 0x2597, 0x2598, /* ▗ ▘ */
  277. 0x2599, 0x259c, /* ▙ ▜ */
  278. 0x259f, 0x259b, /* ▟ ▛ */
  279. 0
  280. };
  281. for(i = 0; norotate[i]; i++)
  282. if(ch == norotate[i])
  283. return ch;
  284. for(i = 0; pairs[i]; i++)
  285. if(ch == pairs[i])
  286. return pairs[i ^ 1];
  287. return ch;
  288. }