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.
 
 
 
 
 
 

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