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.

transform.c 30 KiB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036
  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 horizontal and vertical flipping routines.
  16. */
  17. #include "config.h"
  18. #include "common.h"
  19. #if !defined(__KERNEL__)
  20. # include <stdlib.h>
  21. #endif
  22. #include "cucul.h"
  23. #include "cucul_internals.h"
  24. static uint32_t flipchar(uint32_t ch);
  25. static uint32_t flopchar(uint32_t ch);
  26. static uint32_t rotatechar(uint32_t ch);
  27. static uint32_t leftchar(uint32_t ch);
  28. static uint32_t rightchar(uint32_t ch);
  29. static void leftpair(uint32_t pair[2]);
  30. static void rightpair(uint32_t pair[2]);
  31. /** \brief Invert a canvas' colours.
  32. *
  33. * Invert a canvas' colours (black becomes white, red becomes cyan, etc.)
  34. * without changing the characters in it.
  35. *
  36. * This function never fails.
  37. *
  38. * \param cv The canvas to invert.
  39. * \return This function always returns 0.
  40. */
  41. int cucul_invert(cucul_canvas_t *cv)
  42. {
  43. uint32_t *attrs = cv->attrs;
  44. unsigned int i;
  45. for(i = cv->height * cv->width; i--; )
  46. {
  47. *attrs = *attrs ^ 0x000f000f;
  48. attrs++;
  49. }
  50. return 0;
  51. }
  52. /** \brief Flip a canvas horizontally.
  53. *
  54. * Flip a canvas horizontally, choosing characters that look like the
  55. * mirrored version wherever possible. Some characters will stay
  56. * unchanged by the process, but the operation is guaranteed to be
  57. * involutive: performing it again gives back the original canvas.
  58. *
  59. * This function never fails.
  60. *
  61. * \param cv The canvas to flip.
  62. * \return This function always returns 0.
  63. */
  64. int cucul_flip(cucul_canvas_t *cv)
  65. {
  66. unsigned int y;
  67. for(y = 0; y < cv->height; y++)
  68. {
  69. uint32_t *cleft = cv->chars + y * cv->width;
  70. uint32_t *cright = cleft + cv->width - 1;
  71. uint32_t *aleft = cv->attrs + y * cv->width;
  72. uint32_t *aright = aleft + cv->width - 1;
  73. while(cleft < cright)
  74. {
  75. uint32_t ch;
  76. uint32_t attr;
  77. /* Swap attributes */
  78. attr = *aright;
  79. *aright-- = *aleft;
  80. *aleft++ = attr;
  81. /* Swap characters */
  82. ch = *cright;
  83. *cright-- = flipchar(*cleft);
  84. *cleft++ = flipchar(ch);
  85. }
  86. if(cleft == cright)
  87. *cleft = flipchar(*cleft);
  88. /* Fix fullwidth characters. Could it be done in one loop? */
  89. cleft = cv->chars + y * cv->width;
  90. cright = cleft + cv->width - 1;
  91. for( ; cleft < cright; cleft++)
  92. {
  93. if(cleft[0] == CUCUL_MAGIC_FULLWIDTH)
  94. {
  95. cleft[0] = cleft[1];
  96. cleft[1] = CUCUL_MAGIC_FULLWIDTH;
  97. cleft++;
  98. }
  99. }
  100. }
  101. return 0;
  102. }
  103. /** \brief Flip a canvas vertically.
  104. *
  105. * Flip a canvas vertically, choosing characters that look like the
  106. * mirrored version wherever possible. Some characters will stay
  107. * unchanged by the process, but the operation is guaranteed to be
  108. * involutive: performing it again gives back the original canvas.
  109. *
  110. * This function never fails.
  111. *
  112. * \param cv The canvas to flop.
  113. * \return This function always returns 0.
  114. */
  115. int cucul_flop(cucul_canvas_t *cv)
  116. {
  117. unsigned int x;
  118. for(x = 0; x < cv->width; x++)
  119. {
  120. uint32_t *ctop = cv->chars + x;
  121. uint32_t *cbottom = ctop + cv->width * (cv->height - 1);
  122. uint32_t *atop = cv->attrs + x;
  123. uint32_t *abottom = atop + cv->width * (cv->height - 1);
  124. while(ctop < cbottom)
  125. {
  126. uint32_t ch;
  127. uint32_t attr;
  128. /* Swap attributes */
  129. attr = *abottom; *abottom = *atop; *atop = attr;
  130. /* Swap characters */
  131. ch = *cbottom; *cbottom = flopchar(*ctop); *ctop = flopchar(ch);
  132. ctop += cv->width; cbottom -= cv->width;
  133. atop += cv->width; abottom -= cv->width;
  134. }
  135. if(ctop == cbottom)
  136. *ctop = flopchar(*ctop);
  137. }
  138. return 0;
  139. }
  140. /** \brief Rotate a canvas.
  141. *
  142. * Apply a 180-degree transformation to a canvas, choosing characters
  143. * that look like the upside-down version wherever possible. Some
  144. * characters will stay unchanged by the process, but the operation is
  145. * guaranteed to be involutive: performing it again gives back the
  146. * original canvas.
  147. *
  148. * This function never fails.
  149. *
  150. * \param cv The canvas to rotate.
  151. * \return This function always returns 0.
  152. */
  153. int cucul_rotate_180(cucul_canvas_t *cv)
  154. {
  155. uint32_t *cbegin = cv->chars;
  156. uint32_t *cend = cbegin + cv->width * cv->height - 1;
  157. uint32_t *abegin = cv->attrs;
  158. uint32_t *aend = abegin + cv->width * cv->height - 1;
  159. unsigned int y;
  160. while(cbegin < cend)
  161. {
  162. uint32_t ch;
  163. uint32_t attr;
  164. /* Swap attributes */
  165. attr = *aend; *aend = *abegin; *abegin = attr;
  166. /* Swap characters */
  167. ch = *cend; *cend = rotatechar(*cbegin); *cbegin = rotatechar(ch);
  168. cbegin++; cend--; abegin++; aend--;
  169. }
  170. if(cbegin == cend)
  171. *cbegin = rotatechar(*cbegin);
  172. /* Fix fullwidth characters. Could it be done in one loop? */
  173. for(y = 0; y < cv->height; y++)
  174. {
  175. cbegin = cv->chars + y * cv->width;
  176. cend = cbegin + cv->width - 1;
  177. for( ; cbegin < cend; cbegin++)
  178. {
  179. if(cbegin[0] == CUCUL_MAGIC_FULLWIDTH)
  180. {
  181. cbegin[0] = cbegin[1];
  182. cbegin[1] = CUCUL_MAGIC_FULLWIDTH;
  183. cbegin++;
  184. }
  185. }
  186. }
  187. return 0;
  188. }
  189. /** \brief Rotate a canvas, 90 degrees counterclockwise.
  190. *
  191. * Apply a 90-degree transformation to a canvas, choosing characters
  192. * that look like the rotated version wherever possible. Some characters
  193. * will stay unchanged by the process, some others will be replaced by
  194. * close equivalents. Fullwidth characters will be lost. The operation is
  195. * not guaranteed to be reversible at all.
  196. *
  197. * Note that the width and height of the canvas are swapped.
  198. *
  199. * If an error occurs, -1 is returned and \b errno is set accordingly:
  200. * - \c EBUSY The canvas is in use by a display driver and cannot be rotated.
  201. * - \c ENOMEM Not enough memory to allocate the new canvas size. If this
  202. * happens, the previous canvas handle is still valid.
  203. *
  204. * \param cv The canvas to rotate left.
  205. * \return 0 in case of success, -1 if an error occurred.
  206. */
  207. int cucul_rotate_left(cucul_canvas_t *cv)
  208. {
  209. uint32_t *newchars, *newattrs;
  210. unsigned int x, y;
  211. if(cv->refcount)
  212. {
  213. seterrno(EBUSY);
  214. return -1;
  215. }
  216. /* Save the current frame shortcuts */
  217. _cucul_save_frame_info(cv);
  218. newchars = malloc(cv->width * cv->height * sizeof(uint32_t));
  219. if(!newchars)
  220. return -1;
  221. newattrs = malloc(cv->width * cv->height * sizeof(uint32_t));
  222. if(!newattrs)
  223. {
  224. free(newchars);
  225. return -1;
  226. }
  227. for(y = 0; y < cv->height; y++)
  228. {
  229. for(x = 0; x < cv->width; x++)
  230. {
  231. uint32_t ch, attr;
  232. ch = cv->chars[cv->width * y + x];
  233. attr = cv->attrs[cv->width * y + x];
  234. /* FIXME: do something about fullwidth characters */
  235. ch = leftchar(ch);
  236. newchars[cv->height * (cv->width - 1 - x) + y] = ch;
  237. newattrs[cv->height * (cv->width - 1 - x) + y] = attr;
  238. }
  239. }
  240. free(cv->chars);
  241. free(cv->attrs);
  242. /* Swap X and Y information */
  243. x = cv->frames[cv->frame].x;
  244. y = cv->frames[cv->frame].y;
  245. cv->frames[cv->frame].x = y;
  246. cv->frames[cv->frame].y = cv->width - 1 - x;
  247. x = cv->frames[cv->frame].handlex;
  248. y = cv->frames[cv->frame].handley;
  249. cv->frames[cv->frame].handlex = y;
  250. cv->frames[cv->frame].handley = cv->width - 1 - x;
  251. cv->frames[cv->frame].width = cv->height;
  252. cv->frames[cv->frame].height = cv->width;
  253. cv->frames[cv->frame].chars = newchars;
  254. cv->frames[cv->frame].attrs = newattrs;
  255. /* Reset the current frame shortcuts */
  256. _cucul_load_frame_info(cv);
  257. return 0;
  258. }
  259. /** \brief Rotate a canvas, 90 degrees counterclockwise (widechar version).
  260. *
  261. * Apply a 90-degree transformation to a canvas, choosing characters
  262. * that look like the rotated version wherever possible. Characters cells
  263. * are rotated two-by-two. Some characters will stay unchanged by the
  264. * process, some others will be replaced by close equivalents. Fullwidth
  265. * characters at odd horizontal coordinates will be lost. The operation is
  266. * not guaranteed to be reversible at all.
  267. *
  268. * Note that the width of the canvas is divided by two and becomes the
  269. * new height. Height is multiplied by two and becomes the new width. It
  270. * is illegal to pass a canvas with an odd width to this function.
  271. *
  272. * If an error occurs, -1 is returned and \b errno is set accordingly:
  273. * - \c EBUSY The canvas is in use by a display driver and cannot be rotated.
  274. * - \c EINVAL The canvas' width is odd.
  275. * - \c ENOMEM Not enough memory to allocate the new canvas size. If this
  276. * happens, the previous canvas handle is still valid.
  277. *
  278. * \param cv The canvas to rotate left.
  279. * \return 0 in case of success, -1 if an error occurred.
  280. */
  281. int cucul_rotate_left_wide(cucul_canvas_t *cv)
  282. {
  283. uint32_t *newchars, *newattrs;
  284. unsigned int x, y, subwidth, subheight;
  285. if(cv->refcount)
  286. {
  287. seterrno(EBUSY);
  288. return -1;
  289. }
  290. if(cv->width & 1)
  291. {
  292. seterrno(EINVAL);
  293. return -1;
  294. }
  295. /* Save the current frame shortcuts */
  296. _cucul_save_frame_info(cv);
  297. newchars = malloc(cv->width * cv->height * sizeof(uint32_t));
  298. if(!newchars)
  299. return -1;
  300. newattrs = malloc(cv->width * cv->height * sizeof(uint32_t));
  301. if(!newattrs)
  302. {
  303. free(newchars);
  304. return -1;
  305. }
  306. subwidth = cv->width / 2;
  307. subheight = cv->height;
  308. for(y = 0; y < subheight; y++)
  309. {
  310. for(x = 0; x < subwidth; x++)
  311. {
  312. uint32_t pair[2], attr1, attr2;
  313. pair[0] = cv->chars[(subwidth * y + x) * 2];
  314. attr1 = cv->attrs[(subwidth * y + x) * 2];
  315. pair[1] = cv->chars[(subwidth * y + x) * 2 + 1];
  316. attr2 = cv->attrs[(subwidth * y + x) * 2 + 1];
  317. leftpair(pair);
  318. newchars[(subheight * (subwidth - 1 - x) + y) * 2] = pair[0];
  319. newattrs[(subheight * (subwidth - 1 - x) + y) * 2] = attr1;
  320. newchars[(subheight * (subwidth - 1 - x) + y) * 2 + 1] = pair[1];
  321. newattrs[(subheight * (subwidth - 1 - x) + y) * 2 + 1] = attr2;
  322. }
  323. }
  324. free(cv->chars);
  325. free(cv->attrs);
  326. /* Swap X and Y information */
  327. x = cv->frames[cv->frame].x;
  328. y = cv->frames[cv->frame].y;
  329. cv->frames[cv->frame].x = y * 2;
  330. cv->frames[cv->frame].y = (cv->width - 1 - x) / 2;
  331. x = cv->frames[cv->frame].handlex;
  332. y = cv->frames[cv->frame].handley;
  333. cv->frames[cv->frame].handlex = y * 2;
  334. cv->frames[cv->frame].handley = (cv->width - 1 - x) / 2;
  335. cv->frames[cv->frame].width = cv->height * 2;
  336. cv->frames[cv->frame].height = cv->width / 2;
  337. cv->frames[cv->frame].chars = newchars;
  338. cv->frames[cv->frame].attrs = newattrs;
  339. /* Reset the current frame shortcuts */
  340. _cucul_load_frame_info(cv);
  341. return 0;
  342. }
  343. /** \brief Rotate a canvas, 90 degrees clockwise.
  344. *
  345. * Apply a 270-degree transformation to a canvas, choosing characters
  346. * that look like the rotated version wherever possible. Some characters
  347. * will stay unchanged by the process, some others will be replaced by
  348. * close equivalents. Fullwidth characters will be lost. The operation is
  349. * not guaranteed to be reversible at all.
  350. *
  351. * Note that the width and height of the canvas are swapped.
  352. *
  353. * If an error occurs, -1 is returned and \b errno is set accordingly:
  354. * - \c EBUSY The canvas is in use by a display driver and cannot be rotated.
  355. * - \c ENOMEM Not enough memory to allocate the new canvas size. If this
  356. * happens, the previous canvas handle is still valid.
  357. *
  358. * \param cv The canvas to rotate right.
  359. * \return 0 in case of success, -1 if an error occurred.
  360. */
  361. int cucul_rotate_right(cucul_canvas_t *cv)
  362. {
  363. uint32_t *newchars, *newattrs;
  364. unsigned int x, y;
  365. if(cv->refcount)
  366. {
  367. seterrno(EBUSY);
  368. return -1;
  369. }
  370. /* Save the current frame shortcuts */
  371. _cucul_save_frame_info(cv);
  372. newchars = malloc(cv->width * cv->height * sizeof(uint32_t));
  373. if(!newchars)
  374. {
  375. seterrno(ENOMEM);
  376. return -1;
  377. }
  378. newattrs = malloc(cv->width * cv->height * sizeof(uint32_t));
  379. if(!newattrs)
  380. {
  381. free(newchars);
  382. seterrno(ENOMEM);
  383. return -1;
  384. }
  385. for(y = 0; y < cv->height; y++)
  386. {
  387. for(x = 0; x < cv->width; x++)
  388. {
  389. uint32_t ch, attr;
  390. ch = cv->chars[cv->width * y + x];
  391. attr = cv->attrs[cv->width * y + x];
  392. /* FIXME: do something about fullwidth characters */
  393. ch = rightchar(ch);
  394. newchars[cv->height * x + cv->height - 1 - y] = ch;
  395. newattrs[cv->height * x + cv->height - 1 - y] = attr;
  396. }
  397. }
  398. free(cv->chars);
  399. free(cv->attrs);
  400. /* Swap X and Y information */
  401. x = cv->frames[cv->frame].x;
  402. y = cv->frames[cv->frame].y;
  403. cv->frames[cv->frame].x = cv->height - 1 - y;
  404. cv->frames[cv->frame].y = x;
  405. x = cv->frames[cv->frame].handlex;
  406. y = cv->frames[cv->frame].handley;
  407. cv->frames[cv->frame].handlex = cv->height - 1 - y;
  408. cv->frames[cv->frame].handley = x;
  409. cv->frames[cv->frame].width = cv->height;
  410. cv->frames[cv->frame].height = cv->width;
  411. cv->frames[cv->frame].chars = newchars;
  412. cv->frames[cv->frame].attrs = newattrs;
  413. /* Reset the current frame shortcuts */
  414. _cucul_load_frame_info(cv);
  415. return 0;
  416. }
  417. /** \brief Rotate a canvas, 90 degrees counterclockwise (widechar version).
  418. *
  419. * Apply a 90-degree transformation to a canvas, choosing characters
  420. * that look like the rotated version wherever possible. Characters cells
  421. * are rotated two-by-two. Some characters will stay unchanged by the
  422. * process, some others will be replaced by close equivalents. Fullwidth
  423. * characters at odd horizontal coordinates will be lost. The operation is
  424. * not guaranteed to be reversible at all.
  425. *
  426. * Note that the width of the canvas is divided by two and becomes the
  427. * new height. Height is multiplied by two and becomes the new width. It
  428. * is illegal to pass a canvas with an odd width to this function.
  429. *
  430. * If an error occurs, -1 is returned and \b errno is set accordingly:
  431. * - \c EBUSY The canvas is in use by a display driver and cannot be rotated.
  432. * - \c EINVAL The canvas' width is odd.
  433. * - \c ENOMEM Not enough memory to allocate the new canvas size. If this
  434. * happens, the previous canvas handle is still valid.
  435. *
  436. * \param cv The canvas to rotate right.
  437. * \return 0 in case of success, -1 if an error occurred.
  438. */
  439. int cucul_rotate_right_wide(cucul_canvas_t *cv)
  440. {
  441. uint32_t *newchars, *newattrs;
  442. unsigned int x, y, subwidth, subheight;
  443. if(cv->refcount)
  444. {
  445. seterrno(EBUSY);
  446. return -1;
  447. }
  448. if(cv->width & 1)
  449. {
  450. seterrno(EINVAL);
  451. return -1;
  452. }
  453. /* Save the current frame shortcuts */
  454. _cucul_save_frame_info(cv);
  455. newchars = malloc(cv->width * cv->height * sizeof(uint32_t));
  456. if(!newchars)
  457. return -1;
  458. newattrs = malloc(cv->width * cv->height * sizeof(uint32_t));
  459. if(!newattrs)
  460. {
  461. free(newchars);
  462. return -1;
  463. }
  464. subwidth = cv->width / 2;
  465. subheight = cv->height;
  466. for(y = 0; y < subheight; y++)
  467. {
  468. for(x = 0; x < subwidth; x++)
  469. {
  470. uint32_t pair[2], attr1, attr2;
  471. pair[0] = cv->chars[(subwidth * y + x) * 2];
  472. attr1 = cv->attrs[(subwidth * y + x) * 2];
  473. pair[1] = cv->chars[(subwidth * y + x) * 2 + 1];
  474. attr2 = cv->attrs[(subwidth * y + x) * 2 + 1];
  475. rightpair(pair);
  476. newchars[(subheight * x + subheight - 1 - y) * 2] = pair[0];
  477. newattrs[(subheight * x + subheight - 1 - y) * 2] = attr1;
  478. newchars[(subheight * x + subheight - 1 - y) * 2 + 1] = pair[1];
  479. newattrs[(subheight * x + subheight - 1 - y) * 2 + 1] = attr2;
  480. }
  481. }
  482. free(cv->chars);
  483. free(cv->attrs);
  484. /* Swap X and Y information */
  485. x = cv->frames[cv->frame].x;
  486. y = cv->frames[cv->frame].y;
  487. cv->frames[cv->frame].x = (cv->height - 1 - y) * 2;
  488. cv->frames[cv->frame].y = x / 2;
  489. x = cv->frames[cv->frame].handlex;
  490. y = cv->frames[cv->frame].handley;
  491. cv->frames[cv->frame].handlex = (cv->height - 1 - y) * 2;
  492. cv->frames[cv->frame].handley = x / 2;
  493. cv->frames[cv->frame].width = cv->height * 2;
  494. cv->frames[cv->frame].height = cv->width / 2;
  495. cv->frames[cv->frame].chars = newchars;
  496. cv->frames[cv->frame].attrs = newattrs;
  497. /* Reset the current frame shortcuts */
  498. _cucul_load_frame_info(cv);
  499. return 0;
  500. }
  501. /* FIXME: as the lookup tables grow bigger, use a log(n) lookup instead
  502. * of linear lookup. */
  503. static uint32_t flipchar(uint32_t ch)
  504. {
  505. int i;
  506. static uint32_t const noflip[] =
  507. {
  508. /* ASCII */
  509. ' ', '"', '#', '\'', '-', '.', '*', '+', ':', '=', '0', '8',
  510. 'A', 'H', 'I', 'M', 'O', 'T', 'U', 'V', 'W', 'X', 'Y', '^',
  511. '_', 'i', 'o', 'v', 'w', 'x', '|',
  512. /* CP437 and box drawing */
  513. 0x2591, 0x2592, 0x2593, 0x2588, 0x2584, 0x2580, /* ░ ▒ ▓ █ ▄ ▀ */
  514. 0x2500, 0x2501, 0x2503, 0x2503, 0x253c, 0x254b, /* ─ ━ │ ┃ ┼ ╋ */
  515. 0x252c, 0x2534, 0x2533, 0x253b, 0x2566, 0x2569, /* ┬ ┴ ┳ ┻ ╦ ╩ */
  516. 0x2550, 0x2551, 0x256c, /* ═ ║ ╬ */
  517. 0x2575, 0x2577, 0x2579, 0x257b, /* ╵ ╷ ╹ ╻ */
  518. 0
  519. };
  520. static uint32_t const pairs[] =
  521. {
  522. /* ASCII */
  523. '(', ')',
  524. '/', '\\',
  525. '<', '>',
  526. '[', ']',
  527. 'b', 'd',
  528. 'p', 'q',
  529. '{', '}',
  530. /* ASCII-Unicode */
  531. ';', 0x204f, /* ; ⁏ */
  532. '`', 0x00b4, /* ` ´ */
  533. ',', 0x02ce, /* , ˎ */
  534. 'C', 0x03fd, /* C Ͻ */
  535. 'E', 0x018e, /* E Ǝ */
  536. 'L', 0x2143, /* L ⅃ */
  537. 'N', 0x0418, /* N И */
  538. 'R', 0x042f, /* R Я */
  539. 'S', 0x01a7, /* S Ƨ */
  540. 'c', 0x0254, /* c ɔ */
  541. 'e', 0x0258, /* e ɘ */
  542. /* CP437 */
  543. 0x258c, 0x2590, /* ▌ ▐ */
  544. 0x2596, 0x2597, /* ▖ ▗ */
  545. 0x2598, 0x259d, /* ▘ ▝ */
  546. 0x2599, 0x259f, /* ▙ ▟ */
  547. 0x259a, 0x259e, /* ▚ ▞ */
  548. 0x259b, 0x259c, /* ▛ ▜ */
  549. 0x25ba, 0x25c4, /* ► ◄ */
  550. 0x2192, 0x2190, /* → ← */
  551. 0x2310, 0xac, /* ⌐ ¬ */
  552. /* Box drawing */
  553. 0x250c, 0x2510, /* ┌ ┐ */
  554. 0x2514, 0x2518, /* └ ┘ */
  555. 0x251c, 0x2524, /* ├ ┤ */
  556. 0x250f, 0x2513, /* ┏ ┓ */
  557. 0x2517, 0x251b, /* ┗ ┛ */
  558. 0x2523, 0x252b, /* ┣ ┫ */
  559. 0x2552, 0x2555, /* ╒ ╕ */
  560. 0x2558, 0x255b, /* ╘ ╛ */
  561. 0x2553, 0x2556, /* ╓ ╖ */
  562. 0x2559, 0x255c, /* ╙ ╜ */
  563. 0x2554, 0x2557, /* ╔ ╗ */
  564. 0x255a, 0x255d, /* ╚ ╝ */
  565. 0x255e, 0x2561, /* ╞ ╡ */
  566. 0x255f, 0x2562, /* ╟ ╢ */
  567. 0x2560, 0x2563, /* ╠ ╣ */
  568. 0x2574, 0x2576, /* ╴ ╶ */
  569. 0x2578, 0x257a, /* ╸ ╺ */
  570. 0
  571. };
  572. for(i = 0; noflip[i]; i++)
  573. if(ch == noflip[i])
  574. return ch;
  575. for(i = 0; pairs[i]; i++)
  576. if(ch == pairs[i])
  577. return pairs[i ^ 1];
  578. return ch;
  579. }
  580. static uint32_t flopchar(uint32_t ch)
  581. {
  582. int i;
  583. static uint32_t const noflop[] =
  584. {
  585. /* ASCII */
  586. ' ', '(', ')', '*', '+', '-', '0', '3', '8', ':', '<', '=',
  587. '>', 'B', 'C', 'D', 'E', 'H', 'I', 'K', 'O', 'X', '[', ']',
  588. 'c', 'o', '{', '|', '}',
  589. /* CP437 and box drawing */
  590. 0x2591, 0x2592, 0x2593, 0x2588, 0x258c, 0x2590, /* ░ ▒ ▓ █ ▌ ▐ */
  591. 0x2500, 0x2501, 0x2503, 0x2503, 0x253c, 0x254b, /* ─ ━ │ ┃ ┼ ╋ */
  592. 0x251c, 0x2524, 0x2523, 0x252b, 0x2560, 0x2563, /* ├ ┤ ┣ ┫ ╠ ╣ */
  593. 0x2550, 0x2551, 0x256c, /* ═ ║ ╬ */
  594. 0x2574, 0x2576, 0x2578, 0x257a, /* ╴ ╶ ╸ ╺ */
  595. 0
  596. };
  597. static uint32_t const pairs[] =
  598. {
  599. /* ASCII */
  600. '/', '\\',
  601. 'M', 'W',
  602. ',', '`',
  603. 'b', 'p',
  604. 'd', 'q',
  605. 'p', 'q',
  606. 'f', 't',
  607. '.', '\'',
  608. /* ASCII-Unicode */
  609. '_', 0x203e, /* _ ‾ */
  610. '!', 0x00a1, /* ! ¡ */
  611. 'L', 0x0413, /* L Г */
  612. 'N', 0x0418, /* N И */
  613. 'P', 0x042c, /* P Ь */
  614. 'R', 0x0281, /* R ʁ */
  615. 'S', 0x01a7, /* S Ƨ */
  616. 'U', 0x0548, /* U Ո */
  617. 'V', 0x039b, /* V Λ */
  618. 'Y', 0x2144, /* Y ⅄ */
  619. 'h', 0x03bc, /* h μ */
  620. 'i', 0x1d09, /* i ᴉ */
  621. 'j', 0x1e37, /* j ḷ */
  622. 'l', 0x0237, /* l ȷ */
  623. 'v', 0x028c, /* v ʌ */
  624. 'w', 0x028d, /* w ʍ */
  625. 'y', 0x03bb, /* y λ */
  626. /* Not perfect, but better than nothing */
  627. '"', 0x201e, /* " „ */
  628. 'm', 0x026f, /* m ɯ */
  629. 'n', 'u',
  630. /* CP437 */
  631. 0x2584, 0x2580, /* ▄ ▀ */
  632. 0x2596, 0x2598, /* ▖ ▘ */
  633. 0x2597, 0x259d, /* ▗ ▝ */
  634. 0x2599, 0x259b, /* ▙ ▛ */
  635. 0x259f, 0x259c, /* ▟ ▜ */
  636. 0x259a, 0x259e, /* ▚ ▞ */
  637. /* Box drawing */
  638. 0x250c, 0x2514, /* ┌ └ */
  639. 0x2510, 0x2518, /* ┐ ┘ */
  640. 0x252c, 0x2534, /* ┬ ┴ */
  641. 0x250f, 0x2517, /* ┏ ┗ */
  642. 0x2513, 0x251b, /* ┓ ┛ */
  643. 0x2533, 0x253b, /* ┳ ┻ */
  644. 0x2554, 0x255a, /* ╔ ╚ */
  645. 0x2557, 0x255d, /* ╗ ╝ */
  646. 0x2566, 0x2569, /* ╦ ╩ */
  647. 0x2552, 0x2558, /* ╒ ╘ */
  648. 0x2555, 0x255b, /* ╕ ╛ */
  649. 0x2564, 0x2567, /* ╤ ╧ */
  650. 0x2553, 0x2559, /* ╓ ╙ */
  651. 0x2556, 0x255c, /* ╖ ╜ */
  652. 0x2565, 0x2568, /* ╥ ╨ */
  653. 0x2575, 0x2577, /* ╵ ╷ */
  654. 0x2579, 0x257b, /* ╹ ╻ */
  655. 0
  656. };
  657. for(i = 0; noflop[i]; i++)
  658. if(ch == noflop[i])
  659. return ch;
  660. for(i = 0; pairs[i]; i++)
  661. if(ch == pairs[i])
  662. return pairs[i ^ 1];
  663. return ch;
  664. }
  665. static uint32_t rotatechar(uint32_t ch)
  666. {
  667. int i;
  668. static uint32_t const norotate[] =
  669. {
  670. /* ASCII */
  671. ' ', '*', '+', '-', '/', '0', '8', ':', '=', 'H', 'I', 'N',
  672. 'O', 'S', 'X', 'Z', '\\', 'o', 's', 'x', 'z', '|',
  673. /* Unicode */
  674. 0x2591, 0x2592, 0x2593, 0x2588, 0x259a, 0x259e, /* ░ ▒ ▓ █ ▚ ▞ */
  675. 0x2500, 0x2501, 0x2503, 0x2503, 0x253c, 0x254b, /* ─ ━ │ ┃ ┼ ╋ */
  676. 0x2550, 0x2551, 0x256c, /* ═ ║ ╬ */
  677. 0
  678. };
  679. static uint32_t const pairs[] =
  680. {
  681. /* ASCII */
  682. '(', ')',
  683. '<', '>',
  684. '[', ']',
  685. '{', '}',
  686. '.', '\'',
  687. '6', '9',
  688. 'M', 'W',
  689. 'b', 'q',
  690. 'd', 'p',
  691. 'n', 'u',
  692. /* ASCII-Unicode */
  693. '_', 0x203e, /* _ ‾ */
  694. ',', 0x00b4, /* , ´ */
  695. '`', 0x02ce, /* ` ˎ */
  696. '&', 0x214b, /* & ⅋ */
  697. '!', 0x00a1, /* ! ¡ */
  698. '?', 0x00bf, /* ? ¿ */
  699. 'C', 0x03fd, /* C Ͻ */
  700. 'E', 0x018e, /* E Ǝ */
  701. 'F', 0x2132, /* F Ⅎ */
  702. 'L', 0x2142, /* L ⅂ */
  703. 'U', 0x0548, /* U Ո */
  704. 'V', 0x039b, /* V Λ */
  705. 'Y', 0x2144, /* Y ⅄ */
  706. 'a', 0x0250, /* a ɐ */
  707. 'c', 0x0254, /* c ɔ */
  708. 'e', 0x0259, /* e ə */
  709. 'f', 0x025f, /* f ɟ */
  710. 'g', 0x1d77, /* g ᵷ */
  711. 'h', 0x0265, /* h ɥ */
  712. 'i', 0x1d09, /* i ᴉ */
  713. 'j', 0x1e37, /* j ḷ */
  714. 'k', 0x029e, /* k ʞ */
  715. 'l', 0x0237, /* l ȷ */
  716. 'm', 0x026f, /* m ɯ */
  717. 'r', 0x0279, /* r ɹ */
  718. 't', 0x0287, /* t ʇ */
  719. 'v', 0x028c, /* v ʌ */
  720. 'w', 0x028d, /* w ʍ */
  721. 'y', 0x028e, /* y ʎ */
  722. /* Not perfect, but better than nothing */
  723. '"', 0x201e, /* " „ */
  724. /* Misc Unicode */
  725. 0x00e6, 0x1d02, /* æ ᴂ */
  726. 0x0153, 0x1d14, /* œ ᴔ */
  727. /* CP437 */
  728. 0x258c, 0x2590, /* ▌ ▐ */
  729. 0x2584, 0x2580, /* ▄ ▀ */
  730. 0x2596, 0x259d, /* ▖ ▝ */
  731. 0x2597, 0x2598, /* ▗ ▘ */
  732. 0x2599, 0x259c, /* ▙ ▜ */
  733. 0x259f, 0x259b, /* ▟ ▛ */
  734. /* Box drawing */
  735. 0x250c, 0x2518, /* ┌ ┘ */
  736. 0x2510, 0x2514, /* ┐ └ */
  737. 0x251c, 0x2524, /* ├ ┤ */
  738. 0x252c, 0x2534, /* ┬ ┴ */
  739. 0x250f, 0x251b, /* ┏ ┛ */
  740. 0x2513, 0x2517, /* ┓ ┗ */
  741. 0x2523, 0x252b, /* ┣ ┫ */
  742. 0x2533, 0x253b, /* ┳ ┻ */
  743. 0x2554, 0x255d, /* ╔ ╝ */
  744. 0x2557, 0x255a, /* ╗ ╚ */
  745. 0x2560, 0x2563, /* ╠ ╣ */
  746. 0x2566, 0x2569, /* ╦ ╩ */
  747. 0x2552, 0x255b, /* ╒ ╛ */
  748. 0x2555, 0x2558, /* ╕ ╘ */
  749. 0x255e, 0x2561, /* ╞ ╡ */
  750. 0x2564, 0x2567, /* ╤ ╧ */
  751. 0x2553, 0x255c, /* ╓ ╜ */
  752. 0x2556, 0x2559, /* ╖ ╙ */
  753. 0x255f, 0x2562, /* ╟ ╢ */
  754. 0x2565, 0x2568, /* ╥ ╨ */
  755. 0x2574, 0x2576, /* ╴ ╶ */
  756. 0x2575, 0x2577, /* ╵ ╷ */
  757. 0x2578, 0x257a, /* ╸ ╺ */
  758. 0x2579, 0x257b, /* ╹ ╻ */
  759. 0
  760. };
  761. for(i = 0; norotate[i]; i++)
  762. if(ch == norotate[i])
  763. return ch;
  764. for(i = 0; pairs[i]; i++)
  765. if(ch == pairs[i])
  766. return pairs[i ^ 1];
  767. return ch;
  768. }
  769. static uint32_t const leftright2[] =
  770. {
  771. /* ASCII */
  772. '/', '\\',
  773. '|', '-',
  774. '|', '_', /* This is all right because there was already a '|' before */
  775. /* ASCII-Unicode */
  776. '|', 0x203e, /* | ‾ */
  777. /* Misc Unicode */
  778. 0x2571, 0x2572, /* ╱ ╲ */
  779. /* Box drawing */
  780. 0x2500, 0x2502, /* ─ │ */
  781. 0x2501, 0x2503, /* ━ ┃ */
  782. 0x2550, 0x2551, /* ═ ║ */
  783. 0, 0
  784. };
  785. static uint32_t const leftright4[] =
  786. {
  787. /* ASCII */
  788. '<', 'v', '>', '^',
  789. ',', '.', '\'', '`',
  790. /* ASCII / Unicode */
  791. '(', 0x203f, ')', 0x2040, /* ( ‿ ) ⁀ */
  792. /* Misc Unicode */
  793. 0x256d, 0x2570, 0x256f, 0x256e, /* ╭ ╰ ╯ ╮ */
  794. /* CP437 */
  795. 0x258c, 0x2584, 0x2590, 0x2580, /* ▌ ▄ ▐ ▀ */
  796. 0x2596, 0x2597, 0x259d, 0x2598, /* ▖ ▗ ▝ ▘ */
  797. 0x2599, 0x259f, 0x259c, 0x259b, /* ▙ ▟ ▜ ▛ */
  798. /* Box drawing */
  799. 0x250c, 0x2514, 0x2518, 0x2510, /* ┌ └ ┘ ┐ */
  800. 0x250f, 0x2517, 0x251b, 0x2513, /* ┏ ┗ ┛ ┓ */
  801. 0x251c, 0x2534, 0x2524, 0x252c, /* ├ ┴ ┤ ┬ */
  802. 0x2523, 0x253b, 0x252b, 0x2533, /* ┣ ┻ ┫ ┳ */
  803. 0x2552, 0x2559, 0x255b, 0x2556, /* ╒ ╙ ╛ ╖ */
  804. 0x2553, 0x2558, 0x255c, 0x2555, /* ╓ ╘ ╜ ╕ */
  805. 0x2554, 0x255a, 0x255d, 0x2557, /* ╔ ╚ ╝ ╗ */
  806. 0x255e, 0x2568, 0x2561, 0x2565, /* ╞ ╨ ╡ ╥ */
  807. 0x255f, 0x2567, 0x2562, 0x2564, /* ╟ ╧ ╢ ╤ */
  808. 0x2560, 0x2569, 0x2563, 0x2566, /* ╠ ╩ ╣ ╦ */
  809. 0x2574, 0x2577, 0x2576, 0x2575, /* ╴ ╷ ╶ ╵ */
  810. 0x2578, 0x257b, 0x257a, 0x2579, /* ╸ ╻ ╺ ╹ */
  811. 0, 0, 0, 0
  812. };
  813. static uint32_t leftchar(uint32_t ch)
  814. {
  815. int i;
  816. for(i = 0; leftright2[i]; i++)
  817. if(ch == leftright2[i])
  818. return leftright2[(i & ~1) | ((i + 1) & 1)];
  819. for(i = 0; leftright4[i]; i++)
  820. if(ch == leftright4[i])
  821. return leftright4[(i & ~3) | ((i + 1) & 3)];
  822. return ch;
  823. }
  824. static uint32_t rightchar(uint32_t ch)
  825. {
  826. int i;
  827. for(i = 0; leftright2[i]; i++)
  828. if(ch == leftright2[i])
  829. return leftright2[(i & ~1) | ((i - 1) & 1)];
  830. for(i = 0; leftright4[i]; i++)
  831. if(ch == leftright4[i])
  832. return leftright4[(i & ~3) | ((i - 1) & 3)];
  833. return ch;
  834. }
  835. static uint32_t const leftright2x2[] =
  836. {
  837. /* ASCII / Unicode */
  838. '-', '-', 0x4e28, CUCUL_MAGIC_FULLWIDTH, /* -- 丨 */
  839. 0, 0, 0, 0
  840. };
  841. static uint32_t const leftright2x4[] =
  842. {
  843. /* ASCII */
  844. ':', ' ', '.', '.', ' ', ':', '\'', '\'',
  845. /* ASCII / Unicode */
  846. ' ', '`', 0x00b4, ' ', 0x02ce, ' ', ' ', ',', /* ` ´ ˎ , */
  847. ' ', '`', '\'', ' ', '.', ' ', ' ', ',',
  848. '`', ' ', ',', ' ', ' ', 0x00b4, ' ', 0x02ce, /* ` , ˎ ´ */
  849. '`', ' ', ',', ' ', ' ', '.', ' ', '\'',
  850. '/', ' ', '-', 0x02ce, ' ', '/', '`', '-', /* / -ˎ / `- */
  851. '/', ' ', '-', '.', ' ', '/', '\'', '-',
  852. '\\', ' ', ',', '-', ' ', '\\', '-', 0x00b4, /* \ ,- \ -´ */
  853. '\\', ' ', '.', '-', ' ', '\\', '-', '\'',
  854. '|', ' ', '_', '_', ' ', '|', 0x203e, 0x203e, /* | __ | ‾‾ */
  855. '_', '|', 0x203e, '|', '|', 0x203e, '|', '_', /* _| ‾| |‾ |_ */
  856. '|', '_', '_', '|', 0x203e, '|', '|', 0x203e, /* |_ _| ‾| |‾ */
  857. '_', ' ', ' ', 0x2577, ' ', 0x203e, 0x2575, ' ', /* _ ╷ ‾ ╵ */
  858. ' ', '_', ' ', 0x2575, 0x203e, ' ', 0x2577, ' ', /* _ ╵ ‾ ╷ */
  859. /* Not perfect, but better than nothing */
  860. ' ', '`', '\'', ' ', '.', ' ', ' ', ',',
  861. '`', ' ', ',', ' ', ' ', '.', ' ', '\'',
  862. 0, 0, 0, 0, 0, 0, 0, 0
  863. };
  864. static void leftpair(uint32_t pair[2])
  865. {
  866. int i;
  867. for(i = 0; leftright2x2[i]; i += 2)
  868. if(pair[0] == leftright2x2[i] && pair[1] == leftright2x2[i + 1])
  869. {
  870. pair[0] = leftright2x2[(i & ~3) | ((i + 2) & 3)];
  871. pair[1] = leftright2x2[((i & ~3) | ((i + 2) & 3)) + 1];
  872. return;
  873. }
  874. for(i = 0; leftright2x4[i]; i += 2)
  875. if(pair[0] == leftright2x4[i] && pair[1] == leftright2x4[i + 1])
  876. {
  877. pair[0] = leftright2x4[(i & ~7) | ((i + 2) & 7)];
  878. pair[1] = leftright2x4[((i & ~7) | ((i + 2) & 7)) + 1];
  879. return;
  880. }
  881. }
  882. static void rightpair(uint32_t pair[2])
  883. {
  884. int i;
  885. for(i = 0; leftright2x2[i]; i += 2)
  886. if(pair[0] == leftright2x2[i] && pair[1] == leftright2x2[i + 1])
  887. {
  888. pair[0] = leftright2x2[(i & ~3) | ((i - 2) & 3)];
  889. pair[1] = leftright2x2[((i & ~3) | ((i - 2) & 3)) + 1];
  890. return;
  891. }
  892. for(i = 0; leftright2x4[i]; i += 2)
  893. if(pair[0] == leftright2x4[i] && pair[1] == leftright2x4[i + 1])
  894. {
  895. pair[0] = leftright2x4[(i & ~7) | ((i - 2) & 7)];
  896. pair[1] = leftright2x4[((i & ~7) | ((i - 2) & 7)) + 1];
  897. return;
  898. }
  899. }