Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 
 
 
 

454 рядки
12 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. #include "common.h"
  18. #if !defined(__KERNEL__)
  19. #endif
  20. #include "cucul.h"
  21. #include "cucul_internals.h"
  22. static uint32_t flipchar(uint32_t ch);
  23. static uint32_t flopchar(uint32_t ch);
  24. static uint32_t rotatechar(uint32_t ch);
  25. /** \brief Invert a canvas' colours.
  26. *
  27. * Invert a canvas' colours (black becomes white, red becomes cyan, etc.)
  28. * without changing the characters in it.
  29. *
  30. * This function never fails.
  31. *
  32. * \param cv The canvas to invert.
  33. * \return This function always returns 0.
  34. */
  35. int cucul_invert(cucul_canvas_t *cv)
  36. {
  37. uint32_t *attr = cv->attr;
  38. unsigned int i;
  39. for(i = cv->height * cv->width; i--; )
  40. {
  41. *attr = *attr ^ 0x000f000f;
  42. attr++;
  43. }
  44. return 0;
  45. }
  46. /** \brief Flip a canvas horizontally.
  47. *
  48. * Flip a canvas horizontally, choosing characters that look like the
  49. * mirrored version wherever possible.
  50. *
  51. * This function never fails.
  52. *
  53. * \param cv The canvas to flip.
  54. * \return This function always returns 0.
  55. */
  56. int cucul_flip(cucul_canvas_t *cv)
  57. {
  58. unsigned int y;
  59. for(y = 0; y < cv->height; y++)
  60. {
  61. uint32_t *cleft = cv->chars + y * cv->width;
  62. uint32_t *cright = cleft + cv->width - 1;
  63. uint32_t *aleft = cv->attr + y * cv->width;
  64. uint32_t *aright = aleft + cv->width - 1;
  65. while(cleft < cright)
  66. {
  67. uint32_t ch;
  68. uint32_t attr;
  69. /* Swap attributes */
  70. attr = *aright;
  71. *aright-- = *aleft;
  72. *aleft++ = attr;
  73. /* Swap characters */
  74. ch = *cright;
  75. *cright-- = flipchar(*cleft);
  76. *cleft++ = flipchar(ch);
  77. }
  78. if(cleft == cright)
  79. *cleft = flipchar(*cleft);
  80. /* Fix fullwidth characters. Could it be done in one loop? */
  81. cleft = cv->chars + y * cv->width;
  82. cright = cleft + cv->width - 1;
  83. for( ; cleft < cright; cleft++)
  84. {
  85. if(cleft[0] == CUCUL_MAGIC_FULLWIDTH)
  86. {
  87. cleft[0] = cleft[1];
  88. cleft[1] = CUCUL_MAGIC_FULLWIDTH;
  89. cleft++;
  90. }
  91. }
  92. }
  93. return 0;
  94. }
  95. /** \brief Flip a canvas vertically.
  96. *
  97. * Flip a canvas vertically, choosing characters that look like the
  98. * mirrored version wherever possible.
  99. *
  100. * This function never fails.
  101. *
  102. * \param cv The canvas to flop.
  103. * \return This function always returns 0.
  104. */
  105. int cucul_flop(cucul_canvas_t *cv)
  106. {
  107. unsigned int x;
  108. for(x = 0; x < cv->width; x++)
  109. {
  110. uint32_t *ctop = cv->chars + x;
  111. uint32_t *cbottom = ctop + cv->width * (cv->height - 1);
  112. uint32_t *atop = cv->attr + x;
  113. uint32_t *abottom = atop + cv->width * (cv->height - 1);
  114. while(ctop < cbottom)
  115. {
  116. uint32_t ch;
  117. uint32_t attr;
  118. /* Swap attributes */
  119. attr = *abottom; *abottom = *atop; *atop = attr;
  120. /* Swap characters */
  121. ch = *cbottom; *cbottom = flopchar(*ctop); *ctop = flopchar(ch);
  122. ctop += cv->width; cbottom -= cv->width;
  123. atop += cv->width; abottom -= cv->width;
  124. }
  125. if(ctop == cbottom)
  126. *ctop = flopchar(*ctop);
  127. }
  128. return 0;
  129. }
  130. /** \brief Rotate a canvas.
  131. *
  132. * Apply a 180-degree transformation to a canvas, choosing characters
  133. * that look like the upside-down version wherever possible.
  134. *
  135. * This function never fails.
  136. *
  137. * \param cv The canvas to rotate.
  138. * \return This function always returns 0.
  139. */
  140. int cucul_rotate(cucul_canvas_t *cv)
  141. {
  142. uint32_t *cbegin = cv->chars;
  143. uint32_t *cend = cbegin + cv->width * cv->height - 1;
  144. uint32_t *abegin = cv->attr;
  145. uint32_t *aend = abegin + cv->width * cv->height - 1;
  146. unsigned int y;
  147. while(cbegin < cend)
  148. {
  149. uint32_t ch;
  150. uint32_t attr;
  151. /* Swap attributes */
  152. attr = *aend; *aend = *abegin; *abegin = attr;
  153. /* Swap characters */
  154. ch = *cend; *cend = rotatechar(*cbegin); *cbegin = rotatechar(ch);
  155. cbegin++; cend--; abegin++; aend--;
  156. }
  157. if(cbegin == cend)
  158. *cbegin = rotatechar(*cbegin);
  159. /* Fix fullwidth characters. Could it be done in one loop? */
  160. for(y = 0; y < cv->height; y++)
  161. {
  162. cbegin = cv->chars + y * cv->width;
  163. cend = cbegin + cv->width - 1;
  164. for( ; cbegin < cend; cbegin++)
  165. {
  166. if(cbegin[0] == CUCUL_MAGIC_FULLWIDTH)
  167. {
  168. cbegin[0] = cbegin[1];
  169. cbegin[1] = CUCUL_MAGIC_FULLWIDTH;
  170. cbegin++;
  171. }
  172. }
  173. }
  174. return 0;
  175. }
  176. /* FIXME: as the lookup tables grow bigger, use a log(n) lookup instead
  177. * of linear lookup. */
  178. static uint32_t flipchar(uint32_t ch)
  179. {
  180. int i;
  181. static uint32_t const noflip[] =
  182. {
  183. /* ASCII */
  184. ' ', '"', '#', '\'', '-', '.', '*', '+', ':', '=', '0', '8',
  185. 'A', 'H', 'I', 'M', 'O', 'T', 'U', 'V', 'W', 'X', 'Y', '^',
  186. '_', 'i', 'o', 'v', 'w', 'x', '|',
  187. /* CP437 */
  188. 0x2591, 0x2592, 0x2593, 0x2588, 0x2584, 0x2580, /* ░ ▒ ▓ █ ▄ ▀ */
  189. 0x2500, 0x2501, 0x2503, 0x2503, 0x253c, 0x254b, /* ─ ━ │ ┃ ┼ ╋ */
  190. 0x252c, 0x2534, 0x2533, 0x253b, 0x2566, 0x2569, /* ┬ ┴ ┳ ┻ ╦ ╩ */
  191. 0x2550, 0x2551, 0x256c, /* ═ ║ ╬ */
  192. 0
  193. };
  194. static uint32_t const pairs[] =
  195. {
  196. /* ASCII */
  197. '(', ')',
  198. '/', '\\',
  199. '<', '>',
  200. '[', ']',
  201. 'b', 'd',
  202. 'p', 'q',
  203. '{', '}',
  204. /* ASCII-Unicode */
  205. ';', 0x204f, /* ; ⁏ */
  206. '`', 0x00b4, /* ` ´ */
  207. ',', 0x02ce, /* , ˎ */
  208. 'C', 0x03fd, /* C Ͻ */
  209. 'E', 0x018e, /* E Ǝ */
  210. 'N', 0x0418, /* N И */
  211. 'R', 0x042f, /* R Я */
  212. 'S', 0x01a7, /* S Ƨ */
  213. 'c', 0x0254, /* c ɔ */
  214. 'e', 0x0258, /* e ɘ */
  215. /* CP437 */
  216. 0x258c, 0x2590, /* ▌ ▐ */
  217. 0x2596, 0x2597, /* ▖ ▗ */
  218. 0x2598, 0x259d, /* ▘ ▝ */
  219. 0x2599, 0x259f, /* ▙ ▟ */
  220. 0x259a, 0x259e, /* ▚ ▞ */
  221. 0x259b, 0x259c, /* ▛ ▜ */
  222. 0x25ba, 0x25c4, /* ► ◄ */
  223. 0x2192, 0x2190, /* → ← */
  224. 0x2310, 0xac, /* ⌐ ¬ */
  225. /* Box drawing */
  226. 0x250c, 0x2510, /* ┌ ┐ */
  227. 0x2514, 0x2518, /* └ ┘ */
  228. 0x251c, 0x2524, /* ├ ┤ */
  229. 0x250f, 0x2513, /* ┏ ┓ */
  230. 0x2517, 0x251b, /* ┗ ┛ */
  231. 0x2523, 0x252b, /* ┣ ┫ */
  232. 0x2554, 0x2557, /* ╔ ╗ */
  233. 0x255a, 0x255d, /* ╚ ╝ */
  234. 0x2560, 0x2563, /* ╠ ╣ */
  235. 0
  236. };
  237. for(i = 0; noflip[i]; i++)
  238. if(ch == noflip[i])
  239. return ch;
  240. for(i = 0; pairs[i]; i++)
  241. if(ch == pairs[i])
  242. return pairs[i ^ 1];
  243. return ch;
  244. }
  245. static uint32_t flopchar(uint32_t ch)
  246. {
  247. int i;
  248. static uint32_t const noflop[] =
  249. {
  250. /* ASCII */
  251. ' ', '(', ')', '*', '+', '-', '0', '3', '8', ':', '<', '=',
  252. '>', 'B', 'C', 'D', 'E', 'H', 'I', 'K', 'O', 'X', '[', ']',
  253. 'c', 'o', '{', '|', '}',
  254. /* CP437 */
  255. 0x2591, 0x2592, 0x2593, 0x2588, 0x258c, 0x2590, /* ░ ▒ ▓ █ ▌ ▐ */
  256. 0x2500, 0x2501, 0x2503, 0x2503, 0x253c, 0x254b, /* ─ ━ │ ┃ ┼ ╋ */
  257. 0x251c, 0x2524, 0x2523, 0x252b, 0x2560, 0x2563, /* ├ ┤ ┣ ┫ ╠ ╣ */
  258. 0x2550, 0x2551, 0x256c, /* ═ ║ ╬ */
  259. 0
  260. };
  261. static uint32_t const pairs[] =
  262. {
  263. /* ASCII */
  264. '/', '\\',
  265. 'M', 'W',
  266. ',', '`',
  267. 'b', 'p',
  268. 'd', 'q',
  269. 'p', 'q',
  270. 'f', 't',
  271. '.', '\'',
  272. /* ASCII-Unicode */
  273. '_', 0x203e, /* _ ‾ */
  274. '!', 0x00a1, /* ! ¡ */
  275. 'L', 0x0413, /* L Г */
  276. 'N', 0x0418, /* N И */
  277. 'P', 0x042c, /* P Ь */
  278. 'R', 0x0281, /* R ʁ */
  279. 'S', 0x01a7, /* S Ƨ */
  280. 'U', 0x0548, /* U Ո */
  281. 'V', 0x039b, /* V Λ */
  282. 'h', 0x03bc, /* h μ */
  283. 'i', 0x1d09, /* i ᴉ */
  284. 'v', 0x028c, /* v ʌ */
  285. 'w', 0x028d, /* w ʍ */
  286. 'y', 0x03bb, /* y λ */
  287. /* Not perfect, but better than nothing */
  288. '"', 0x201e, /* " „ */
  289. 'm', 0x026f, /* m ɯ */
  290. 'n', 'u',
  291. /* CP437 */
  292. 0x2584, 0x2580, /* ▄ ▀ */
  293. 0x2596, 0x2598, /* ▖ ▘ */
  294. 0x2597, 0x259d, /* ▗ ▝ */
  295. 0x2599, 0x259b, /* ▙ ▛ */
  296. 0x259f, 0x259c, /* ▟ ▜ */
  297. 0x259a, 0x259e, /* ▚ ▞ */
  298. /* Box drawing */
  299. 0x250c, 0x2514, /* ┌ └ */
  300. 0x2510, 0x2518, /* ┐ ┘ */
  301. 0x252c, 0x2534, /* ┬ ┴ */
  302. 0x250f, 0x2517, /* ┏ ┗ */
  303. 0x2513, 0x251b, /* ┓ ┛ */
  304. 0x2533, 0x253b, /* ┳ ┻ */
  305. 0x2554, 0x255a, /* ╔ ╚ */
  306. 0x2557, 0x255d, /* ╗ ╝ */
  307. 0x2566, 0x2569, /* ╦ ╩ */
  308. 0
  309. };
  310. for(i = 0; noflop[i]; i++)
  311. if(ch == noflop[i])
  312. return ch;
  313. for(i = 0; pairs[i]; i++)
  314. if(ch == pairs[i])
  315. return pairs[i ^ 1];
  316. return ch;
  317. }
  318. static uint32_t rotatechar(uint32_t ch)
  319. {
  320. int i;
  321. static uint32_t const norotate[] =
  322. {
  323. /* ASCII */
  324. ' ', '*', '+', '-', '/', '0', '8', ':', '=', 'H', 'I', 'N',
  325. 'O', 'S', 'X', 'Z', '\\', 'l', 'o', 's', 'x', 'z', '|',
  326. /* Unicode */
  327. 0x2591, 0x2592, 0x2593, 0x2588, 0x259a, 0x259e, /* ░ ▒ ▓ █ ▚ ▞ */
  328. 0x2500, 0x2501, 0x2503, 0x2503, 0x253c, 0x254b, /* ─ ━ │ ┃ ┼ ╋ */
  329. 0x2550, 0x2551, 0x256c, /* ═ ║ ╬ */
  330. 0
  331. };
  332. static uint32_t const pairs[] =
  333. {
  334. /* ASCII */
  335. '(', ')',
  336. '<', '>',
  337. '[', ']',
  338. '{', '}',
  339. '.', '\'',
  340. '6', '9',
  341. 'M', 'W',
  342. 'b', 'q',
  343. 'd', 'p',
  344. 'n', 'u',
  345. /* ASCII-Unicode */
  346. '_', 0x203e, /* _ ‾ */
  347. ',', 0x00b4, /* , ´ */
  348. '`', 0x02ce, /* ` ˎ */
  349. '&', 0x214b, /* & ⅋ */
  350. '!', 0x00a1, /* ! ¡ */
  351. '?', 0x00bf, /* ? ¿ */
  352. 'C', 0x03fd, /* C Ͻ */
  353. 'E', 0x018e, /* E Ǝ */
  354. 'F', 0x2132, /* F Ⅎ */
  355. 'U', 0x0548, /* U Ո */
  356. 'V', 0x039b, /* V Λ */
  357. 'a', 0x0250, /* a ɐ */
  358. 'c', 0x0254, /* c ɔ */
  359. 'e', 0x0259, /* e ə */
  360. 'f', 0x025f, /* f ɟ */
  361. 'g', 0x1d77, /* g ᵷ */
  362. 'h', 0x0265, /* h ɥ */
  363. 'i', 0x1d09, /* i ᴉ */
  364. 'k', 0x029e, /* k ʞ */
  365. 'm', 0x026f, /* m ɯ */
  366. 'r', 0x0279, /* r ɹ */
  367. 't', 0x0287, /* t ʇ */
  368. 'v', 0x028c, /* v ʌ */
  369. 'w', 0x028d, /* w ʍ */
  370. 'y', 0x028e, /* y ʎ */
  371. /* Not perfect, but better than nothing */
  372. '"', 0x201e, /* " „ */
  373. /* CP437 */
  374. 0x258c, 0x2590, /* ▌ ▐ */
  375. 0x2584, 0x2580, /* ▄ ▀ */
  376. 0x2596, 0x259d, /* ▖ ▝ */
  377. 0x2597, 0x2598, /* ▗ ▘ */
  378. 0x2599, 0x259c, /* ▙ ▜ */
  379. 0x259f, 0x259b, /* ▟ ▛ */
  380. /* Box drawing */
  381. 0x250c, 0x2518, /* ┌ ┘ */
  382. 0x2510, 0x2514, /* ┐ └ */
  383. 0x251c, 0x2524, /* ├ ┤ */
  384. 0x252c, 0x2534, /* ┬ ┴ */
  385. 0x250f, 0x251b, /* ┏ ┛ */
  386. 0x2513, 0x2517, /* ┓ ┗ */
  387. 0x2523, 0x252b, /* ┣ ┫ */
  388. 0x2533, 0x253b, /* ┳ ┻ */
  389. 0x2554, 0x255d, /* ╔ ╝ */
  390. 0x2557, 0x255a, /* ╗ ╚ */
  391. 0x2560, 0x2563, /* ╠ ╣ */
  392. 0x2566, 0x2569, /* ╦ ╩ */
  393. 0
  394. };
  395. for(i = 0; norotate[i]; i++)
  396. if(ch == norotate[i])
  397. return ch;
  398. for(i = 0; pairs[i]; i++)
  399. if(ch == pairs[i])
  400. return pairs[i ^ 1];
  401. return ch;
  402. }