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.
 
 
 
 
 
 

1085 lines
33 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. 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. Characters cells
  193. * are rotated two-by-two. Some characters will stay unchanged by the
  194. * process, some others will be replaced by close equivalents. Fullwidth
  195. * characters at odd horizontal coordinates will be lost. The operation is
  196. * not guaranteed to be reversible at all.
  197. *
  198. * Note that the width of the canvas is divided by two and becomes the
  199. * new height. Height is multiplied by two and becomes the new width. If
  200. * the original width is an odd number, the division is rounded up.
  201. *
  202. * If an error occurs, -1 is returned and \b errno is set accordingly:
  203. * - \c EBUSY The canvas is in use by a display driver and cannot be rotated.
  204. * - \c ENOMEM Not enough memory to allocate the new canvas size. If this
  205. * happens, the previous canvas handle is still valid.
  206. *
  207. * \param cv The canvas to rotate left.
  208. * \return 0 in case of success, -1 if an error occurred.
  209. */
  210. int cucul_rotate_left(cucul_canvas_t *cv)
  211. {
  212. uint32_t *newchars, *newattrs;
  213. unsigned int x, y, w2, h2;
  214. if(cv->refcount)
  215. {
  216. seterrno(EBUSY);
  217. return -1;
  218. }
  219. /* Save the current frame shortcuts */
  220. _cucul_save_frame_info(cv);
  221. w2 = (cv->width + 1) / 2;
  222. h2 = cv->height;
  223. newchars = malloc(w2 * h2 * 2 * sizeof(uint32_t));
  224. if(!newchars)
  225. {
  226. seterrno(ENOMEM);
  227. return -1;
  228. }
  229. newattrs = malloc(w2 * h2 * 2 * sizeof(uint32_t));
  230. if(!newattrs)
  231. {
  232. free(newchars);
  233. seterrno(ENOMEM);
  234. return -1;
  235. }
  236. for(y = 0; y < h2; y++)
  237. {
  238. for(x = 0; x < w2; x++)
  239. {
  240. uint32_t pair[2], attr1, attr2;
  241. pair[0] = cv->chars[cv->width * y + x * 2];
  242. attr1 = cv->attrs[cv->width * y + x * 2];
  243. if((cv->width & 1) && x == w2 - 1)
  244. {
  245. /* Special case: odd column */
  246. pair[1] = ' ';
  247. attr2 = attr1;
  248. }
  249. else
  250. {
  251. pair[1] = cv->chars[cv->width * y + x * 2 + 1];
  252. attr2 = cv->attrs[cv->width * y + x * 2 + 1];
  253. }
  254. leftpair(pair);
  255. newchars[(h2 * (w2 - 1 - x) + y) * 2] = pair[0];
  256. newattrs[(h2 * (w2 - 1 - x) + y) * 2] = attr1;
  257. newchars[(h2 * (w2 - 1 - x) + y) * 2 + 1] = pair[1];
  258. newattrs[(h2 * (w2 - 1 - x) + y) * 2 + 1] = attr2;
  259. }
  260. }
  261. free(cv->chars);
  262. free(cv->attrs);
  263. /* Swap X and Y information */
  264. x = cv->frames[cv->frame].x;
  265. y = cv->frames[cv->frame].y;
  266. cv->frames[cv->frame].x = y * 2;
  267. cv->frames[cv->frame].y = (cv->width - 1 - x) / 2;
  268. x = cv->frames[cv->frame].handlex;
  269. y = cv->frames[cv->frame].handley;
  270. cv->frames[cv->frame].handlex = y * 2;
  271. cv->frames[cv->frame].handley = (cv->width - 1 - x) / 2;
  272. cv->frames[cv->frame].width = cv->height * 2;
  273. cv->frames[cv->frame].height = (cv->width + 1) / 2;
  274. cv->frames[cv->frame].chars = newchars;
  275. cv->frames[cv->frame].attrs = newattrs;
  276. /* Reset the current frame shortcuts */
  277. _cucul_load_frame_info(cv);
  278. return 0;
  279. }
  280. /** \brief Rotate a canvas, 90 degrees counterclockwise.
  281. *
  282. * Apply a 90-degree transformation to a canvas, choosing characters
  283. * that look like the rotated version wherever possible. Characters cells
  284. * are rotated two-by-two. Some characters will stay unchanged by the
  285. * process, some others will be replaced by close equivalents. Fullwidth
  286. * characters at odd horizontal coordinates will be lost. The operation is
  287. * not guaranteed to be reversible at all.
  288. *
  289. * Note that the width of the canvas is divided by two and becomes the
  290. * new height. Height is multiplied by two and becomes the new width. If
  291. * the original width is an odd number, the division is rounded up.
  292. *
  293. * If an error occurs, -1 is returned and \b errno is set accordingly:
  294. * - \c EBUSY The canvas is in use by a display driver and cannot be rotated.
  295. * - \c ENOMEM Not enough memory to allocate the new canvas size. If this
  296. * happens, the previous canvas handle is still valid.
  297. *
  298. * \param cv The canvas to rotate right.
  299. * \return 0 in case of success, -1 if an error occurred.
  300. */
  301. int cucul_rotate_right(cucul_canvas_t *cv)
  302. {
  303. uint32_t *newchars, *newattrs;
  304. unsigned int x, y, w2, h2;
  305. if(cv->refcount)
  306. {
  307. seterrno(EBUSY);
  308. return -1;
  309. }
  310. /* Save the current frame shortcuts */
  311. _cucul_save_frame_info(cv);
  312. w2 = (cv->width + 1) / 2;
  313. h2 = cv->height;
  314. newchars = malloc(w2 * h2 * 2 * sizeof(uint32_t));
  315. if(!newchars)
  316. {
  317. seterrno(ENOMEM);
  318. return -1;
  319. }
  320. newattrs = malloc(w2 * h2 * 2 * sizeof(uint32_t));
  321. if(!newattrs)
  322. {
  323. free(newchars);
  324. seterrno(ENOMEM);
  325. return -1;
  326. }
  327. for(y = 0; y < h2; y++)
  328. {
  329. for(x = 0; x < w2; x++)
  330. {
  331. uint32_t pair[2], attr1, attr2;
  332. pair[0] = cv->chars[cv->width * y + x * 2];
  333. attr1 = cv->attrs[cv->width * y + x * 2];
  334. if((cv->width & 1) && x == w2 - 1)
  335. {
  336. /* Special case: odd column */
  337. pair[1] = ' ';
  338. attr2 = attr1;
  339. }
  340. else
  341. {
  342. pair[1] = cv->chars[cv->width * y + x * 2 + 1];
  343. attr2 = cv->attrs[cv->width * y + x * 2 + 1];
  344. }
  345. rightpair(pair);
  346. newchars[(h2 * x + h2 - 1 - y) * 2] = pair[0];
  347. newattrs[(h2 * x + h2 - 1 - y) * 2] = attr1;
  348. newchars[(h2 * x + h2 - 1 - y) * 2 + 1] = pair[1];
  349. newattrs[(h2 * x + h2 - 1 - y) * 2 + 1] = attr2;
  350. }
  351. }
  352. free(cv->chars);
  353. free(cv->attrs);
  354. /* Swap X and Y information */
  355. x = cv->frames[cv->frame].x;
  356. y = cv->frames[cv->frame].y;
  357. cv->frames[cv->frame].x = (cv->height - 1 - y) * 2;
  358. cv->frames[cv->frame].y = x / 2;
  359. x = cv->frames[cv->frame].handlex;
  360. y = cv->frames[cv->frame].handley;
  361. cv->frames[cv->frame].handlex = (cv->height - 1 - y) * 2;
  362. cv->frames[cv->frame].handley = x / 2;
  363. cv->frames[cv->frame].width = cv->height * 2;
  364. cv->frames[cv->frame].height = (cv->width + 1) / 2;
  365. cv->frames[cv->frame].chars = newchars;
  366. cv->frames[cv->frame].attrs = newattrs;
  367. /* Reset the current frame shortcuts */
  368. _cucul_load_frame_info(cv);
  369. return 0;
  370. }
  371. /** \brief Rotate and stretch a canvas, 90 degrees counterclockwise.
  372. *
  373. * Apply a 90-degree transformation to a canvas, choosing characters
  374. * that look like the rotated version wherever possible. Some characters
  375. * will stay unchanged by the process, some others will be replaced by
  376. * close equivalents. Fullwidth characters will be lost. The operation is
  377. * not guaranteed to be reversible at all.
  378. *
  379. * Note that the width and height of the canvas are swapped, causing its
  380. * aspect ratio to look stretched.
  381. *
  382. * If an error occurs, -1 is returned and \b errno is set accordingly:
  383. * - \c EBUSY The canvas is in use by a display driver and cannot be rotated.
  384. * - \c ENOMEM Not enough memory to allocate the new canvas size. If this
  385. * happens, the previous canvas handle is still valid.
  386. *
  387. * \param cv The canvas to rotate left.
  388. * \return 0 in case of success, -1 if an error occurred.
  389. */
  390. int cucul_stretch_left(cucul_canvas_t *cv)
  391. {
  392. uint32_t *newchars, *newattrs;
  393. unsigned int x, y;
  394. if(cv->refcount)
  395. {
  396. seterrno(EBUSY);
  397. return -1;
  398. }
  399. /* Save the current frame shortcuts */
  400. _cucul_save_frame_info(cv);
  401. newchars = malloc(cv->width * cv->height * sizeof(uint32_t));
  402. if(!newchars)
  403. {
  404. seterrno(ENOMEM);
  405. return -1;
  406. }
  407. newattrs = malloc(cv->width * cv->height * sizeof(uint32_t));
  408. if(!newattrs)
  409. {
  410. free(newchars);
  411. seterrno(ENOMEM);
  412. return -1;
  413. }
  414. for(y = 0; y < cv->height; y++)
  415. {
  416. for(x = 0; x < cv->width; x++)
  417. {
  418. uint32_t ch, attr;
  419. ch = cv->chars[cv->width * y + x];
  420. attr = cv->attrs[cv->width * y + x];
  421. /* FIXME: do something about fullwidth characters */
  422. ch = leftchar(ch);
  423. newchars[cv->height * (cv->width - 1 - x) + y] = ch;
  424. newattrs[cv->height * (cv->width - 1 - x) + y] = attr;
  425. }
  426. }
  427. free(cv->chars);
  428. free(cv->attrs);
  429. /* Swap X and Y information */
  430. x = cv->frames[cv->frame].x;
  431. y = cv->frames[cv->frame].y;
  432. cv->frames[cv->frame].x = y;
  433. cv->frames[cv->frame].y = cv->width - 1 - x;
  434. x = cv->frames[cv->frame].handlex;
  435. y = cv->frames[cv->frame].handley;
  436. cv->frames[cv->frame].handlex = y;
  437. cv->frames[cv->frame].handley = cv->width - 1 - x;
  438. cv->frames[cv->frame].width = cv->height;
  439. cv->frames[cv->frame].height = cv->width;
  440. cv->frames[cv->frame].chars = newchars;
  441. cv->frames[cv->frame].attrs = newattrs;
  442. /* Reset the current frame shortcuts */
  443. _cucul_load_frame_info(cv);
  444. return 0;
  445. }
  446. /** \brief Rotate and stretch a canvas, 90 degrees clockwise.
  447. *
  448. * Apply a 270-degree transformation to a canvas, choosing characters
  449. * that look like the rotated version wherever possible. Some characters
  450. * will stay unchanged by the process, some others will be replaced by
  451. * close equivalents. Fullwidth characters will be lost. The operation is
  452. * not guaranteed to be reversible at all.
  453. *
  454. * Note that the width and height of the canvas are swapped, causing its
  455. * aspect ratio to look stretched.
  456. *
  457. * If an error occurs, -1 is returned and \b errno is set accordingly:
  458. * - \c EBUSY The canvas is in use by a display driver and cannot be rotated.
  459. * - \c ENOMEM Not enough memory to allocate the new canvas size. If this
  460. * happens, the previous canvas handle is still valid.
  461. *
  462. * \param cv The canvas to rotate right.
  463. * \return 0 in case of success, -1 if an error occurred.
  464. */
  465. int cucul_stretch_right(cucul_canvas_t *cv)
  466. {
  467. uint32_t *newchars, *newattrs;
  468. unsigned int x, y;
  469. if(cv->refcount)
  470. {
  471. seterrno(EBUSY);
  472. return -1;
  473. }
  474. /* Save the current frame shortcuts */
  475. _cucul_save_frame_info(cv);
  476. newchars = malloc(cv->width * cv->height * sizeof(uint32_t));
  477. if(!newchars)
  478. {
  479. seterrno(ENOMEM);
  480. return -1;
  481. }
  482. newattrs = malloc(cv->width * cv->height * sizeof(uint32_t));
  483. if(!newattrs)
  484. {
  485. free(newchars);
  486. seterrno(ENOMEM);
  487. return -1;
  488. }
  489. for(y = 0; y < cv->height; y++)
  490. {
  491. for(x = 0; x < cv->width; x++)
  492. {
  493. uint32_t ch, attr;
  494. ch = cv->chars[cv->width * y + x];
  495. attr = cv->attrs[cv->width * y + x];
  496. /* FIXME: do something about fullwidth characters */
  497. ch = rightchar(ch);
  498. newchars[cv->height * x + cv->height - 1 - y] = ch;
  499. newattrs[cv->height * x + cv->height - 1 - y] = attr;
  500. }
  501. }
  502. free(cv->chars);
  503. free(cv->attrs);
  504. /* Swap X and Y information */
  505. x = cv->frames[cv->frame].x;
  506. y = cv->frames[cv->frame].y;
  507. cv->frames[cv->frame].x = cv->height - 1 - y;
  508. cv->frames[cv->frame].y = x;
  509. x = cv->frames[cv->frame].handlex;
  510. y = cv->frames[cv->frame].handley;
  511. cv->frames[cv->frame].handlex = cv->height - 1 - y;
  512. cv->frames[cv->frame].handley = x;
  513. cv->frames[cv->frame].width = cv->height;
  514. cv->frames[cv->frame].height = cv->width;
  515. cv->frames[cv->frame].chars = newchars;
  516. cv->frames[cv->frame].attrs = newattrs;
  517. /* Reset the current frame shortcuts */
  518. _cucul_load_frame_info(cv);
  519. return 0;
  520. }
  521. /* FIXME: as the lookup tables grow bigger, use a log(n) lookup instead
  522. * of linear lookup. */
  523. static uint32_t flipchar(uint32_t ch)
  524. {
  525. int i;
  526. static uint32_t const noflip[] =
  527. {
  528. /* ASCII */
  529. ' ', '"', '#', '\'', '-', '.', '*', '+', ':', '=', '0', '8',
  530. 'A', 'H', 'I', 'M', 'O', 'T', 'U', 'V', 'W', 'X', 'Y', '^',
  531. '_', 'i', 'o', 'v', 'w', 'x', '|',
  532. /* CP437 and box drawing */
  533. 0x2591, 0x2592, 0x2593, 0x2588, 0x2584, 0x2580, /* ░ ▒ ▓ █ ▄ ▀ */
  534. 0x2500, 0x2501, 0x2503, 0x2503, 0x253c, 0x254b, /* ─ ━ │ ┃ ┼ ╋ */
  535. 0x252c, 0x2534, 0x2533, 0x253b, 0x2566, 0x2569, /* ┬ ┴ ┳ ┻ ╦ ╩ */
  536. 0x2550, 0x2551, 0x256c, /* ═ ║ ╬ */
  537. 0x2575, 0x2577, 0x2579, 0x257b, /* ╵ ╷ ╹ ╻ */
  538. 0
  539. };
  540. static uint32_t const pairs[] =
  541. {
  542. /* ASCII */
  543. '(', ')',
  544. '/', '\\',
  545. '<', '>',
  546. '[', ']',
  547. 'b', 'd',
  548. 'p', 'q',
  549. '{', '}',
  550. /* ASCII-Unicode */
  551. ';', 0x204f, /* ; ⁏ */
  552. '`', 0x00b4, /* ` ´ */
  553. ',', 0x02ce, /* , ˎ */
  554. 'C', 0x03fd, /* C Ͻ */
  555. 'E', 0x018e, /* E Ǝ */
  556. 'L', 0x2143, /* L ⅃ */
  557. 'N', 0x0418, /* N И */
  558. 'R', 0x042f, /* R Я */
  559. 'S', 0x01a7, /* S Ƨ */
  560. 'c', 0x0254, /* c ɔ */
  561. 'e', 0x0258, /* e ɘ */
  562. /* CP437 */
  563. 0x258c, 0x2590, /* ▌ ▐ */
  564. 0x2596, 0x2597, /* ▖ ▗ */
  565. 0x2598, 0x259d, /* ▘ ▝ */
  566. 0x2599, 0x259f, /* ▙ ▟ */
  567. 0x259a, 0x259e, /* ▚ ▞ */
  568. 0x259b, 0x259c, /* ▛ ▜ */
  569. 0x25ba, 0x25c4, /* ► ◄ */
  570. 0x2192, 0x2190, /* → ← */
  571. 0x2310, 0xac, /* ⌐ ¬ */
  572. /* Box drawing */
  573. 0x250c, 0x2510, /* ┌ ┐ */
  574. 0x2514, 0x2518, /* └ ┘ */
  575. 0x251c, 0x2524, /* ├ ┤ */
  576. 0x250f, 0x2513, /* ┏ ┓ */
  577. 0x2517, 0x251b, /* ┗ ┛ */
  578. 0x2523, 0x252b, /* ┣ ┫ */
  579. 0x2552, 0x2555, /* ╒ ╕ */
  580. 0x2558, 0x255b, /* ╘ ╛ */
  581. 0x2553, 0x2556, /* ╓ ╖ */
  582. 0x2559, 0x255c, /* ╙ ╜ */
  583. 0x2554, 0x2557, /* ╔ ╗ */
  584. 0x255a, 0x255d, /* ╚ ╝ */
  585. 0x255e, 0x2561, /* ╞ ╡ */
  586. 0x255f, 0x2562, /* ╟ ╢ */
  587. 0x2560, 0x2563, /* ╠ ╣ */
  588. 0x2574, 0x2576, /* ╴ ╶ */
  589. 0x2578, 0x257a, /* ╸ ╺ */
  590. 0
  591. };
  592. for(i = 0; noflip[i]; i++)
  593. if(ch == noflip[i])
  594. return ch;
  595. for(i = 0; pairs[i]; i++)
  596. if(ch == pairs[i])
  597. return pairs[i ^ 1];
  598. return ch;
  599. }
  600. static uint32_t flopchar(uint32_t ch)
  601. {
  602. int i;
  603. static uint32_t const noflop[] =
  604. {
  605. /* ASCII */
  606. ' ', '(', ')', '*', '+', '-', '0', '3', '8', ':', '<', '=',
  607. '>', 'B', 'C', 'D', 'E', 'H', 'I', 'K', 'O', 'X', '[', ']',
  608. 'c', 'o', '{', '|', '}',
  609. /* CP437 and box drawing */
  610. 0x2591, 0x2592, 0x2593, 0x2588, 0x258c, 0x2590, /* ░ ▒ ▓ █ ▌ ▐ */
  611. 0x2500, 0x2501, 0x2503, 0x2503, 0x253c, 0x254b, /* ─ ━ │ ┃ ┼ ╋ */
  612. 0x251c, 0x2524, 0x2523, 0x252b, 0x2560, 0x2563, /* ├ ┤ ┣ ┫ ╠ ╣ */
  613. 0x2550, 0x2551, 0x256c, /* ═ ║ ╬ */
  614. 0x2574, 0x2576, 0x2578, 0x257a, /* ╴ ╶ ╸ ╺ */
  615. 0
  616. };
  617. static uint32_t const pairs[] =
  618. {
  619. /* ASCII */
  620. '/', '\\',
  621. 'M', 'W',
  622. ',', '`',
  623. 'b', 'p',
  624. 'd', 'q',
  625. 'p', 'q',
  626. 'f', 't',
  627. '.', '\'',
  628. /* ASCII-Unicode */
  629. '_', 0x203e, /* _ ‾ */
  630. '!', 0x00a1, /* ! ¡ */
  631. 'L', 0x0413, /* L Г */
  632. 'N', 0x0418, /* N И */
  633. 'P', 0x042c, /* P Ь */
  634. 'R', 0x0281, /* R ʁ */
  635. 'S', 0x01a7, /* S Ƨ */
  636. 'U', 0x0548, /* U Ո */
  637. 'V', 0x039b, /* V Λ */
  638. 'Y', 0x2144, /* Y ⅄ */
  639. 'h', 0x03bc, /* h μ */
  640. 'i', 0x1d09, /* i ᴉ */
  641. 'j', 0x1e37, /* j ḷ */
  642. 'l', 0x0237, /* l ȷ */
  643. 'v', 0x028c, /* v ʌ */
  644. 'w', 0x028d, /* w ʍ */
  645. 'y', 0x03bb, /* y λ */
  646. /* Not perfect, but better than nothing */
  647. '"', 0x201e, /* " „ */
  648. 'm', 0x026f, /* m ɯ */
  649. 'n', 'u',
  650. /* CP437 */
  651. 0x2584, 0x2580, /* ▄ ▀ */
  652. 0x2596, 0x2598, /* ▖ ▘ */
  653. 0x2597, 0x259d, /* ▗ ▝ */
  654. 0x2599, 0x259b, /* ▙ ▛ */
  655. 0x259f, 0x259c, /* ▟ ▜ */
  656. 0x259a, 0x259e, /* ▚ ▞ */
  657. /* Box drawing */
  658. 0x250c, 0x2514, /* ┌ └ */
  659. 0x2510, 0x2518, /* ┐ ┘ */
  660. 0x252c, 0x2534, /* ┬ ┴ */
  661. 0x250f, 0x2517, /* ┏ ┗ */
  662. 0x2513, 0x251b, /* ┓ ┛ */
  663. 0x2533, 0x253b, /* ┳ ┻ */
  664. 0x2554, 0x255a, /* ╔ ╚ */
  665. 0x2557, 0x255d, /* ╗ ╝ */
  666. 0x2566, 0x2569, /* ╦ ╩ */
  667. 0x2552, 0x2558, /* ╒ ╘ */
  668. 0x2555, 0x255b, /* ╕ ╛ */
  669. 0x2564, 0x2567, /* ╤ ╧ */
  670. 0x2553, 0x2559, /* ╓ ╙ */
  671. 0x2556, 0x255c, /* ╖ ╜ */
  672. 0x2565, 0x2568, /* ╥ ╨ */
  673. 0x2575, 0x2577, /* ╵ ╷ */
  674. 0x2579, 0x257b, /* ╹ ╻ */
  675. 0
  676. };
  677. for(i = 0; noflop[i]; i++)
  678. if(ch == noflop[i])
  679. return ch;
  680. for(i = 0; pairs[i]; i++)
  681. if(ch == pairs[i])
  682. return pairs[i ^ 1];
  683. return ch;
  684. }
  685. static uint32_t rotatechar(uint32_t ch)
  686. {
  687. int i;
  688. static uint32_t const norotate[] =
  689. {
  690. /* ASCII */
  691. ' ', '*', '+', '-', '/', '0', '8', ':', '=', 'H', 'I', 'N',
  692. 'O', 'S', 'X', 'Z', '\\', 'o', 's', 'x', 'z', '|',
  693. /* Unicode */
  694. 0x2591, 0x2592, 0x2593, 0x2588, 0x259a, 0x259e, /* ░ ▒ ▓ █ ▚ ▞ */
  695. 0x2500, 0x2501, 0x2503, 0x2503, 0x253c, 0x254b, /* ─ ━ │ ┃ ┼ ╋ */
  696. 0x2550, 0x2551, 0x256c, /* ═ ║ ╬ */
  697. 0
  698. };
  699. static uint32_t const pairs[] =
  700. {
  701. /* ASCII */
  702. '(', ')',
  703. '<', '>',
  704. '[', ']',
  705. '{', '}',
  706. '.', '\'',
  707. '6', '9',
  708. 'M', 'W',
  709. 'b', 'q',
  710. 'd', 'p',
  711. 'n', 'u',
  712. /* ASCII-Unicode */
  713. '_', 0x203e, /* _ ‾ */
  714. ',', 0x00b4, /* , ´ */
  715. '`', 0x02ce, /* ` ˎ */
  716. '&', 0x214b, /* & ⅋ */
  717. '!', 0x00a1, /* ! ¡ */
  718. '?', 0x00bf, /* ? ¿ */
  719. 'C', 0x03fd, /* C Ͻ */
  720. 'E', 0x018e, /* E Ǝ */
  721. 'F', 0x2132, /* F Ⅎ */
  722. 'L', 0x2142, /* L ⅂ */
  723. 'U', 0x0548, /* U Ո */
  724. 'V', 0x039b, /* V Λ */
  725. 'Y', 0x2144, /* Y ⅄ */
  726. 'a', 0x0250, /* a ɐ */
  727. 'c', 0x0254, /* c ɔ */
  728. 'e', 0x0259, /* e ə */
  729. 'f', 0x025f, /* f ɟ */
  730. 'g', 0x1d77, /* g ᵷ */
  731. 'h', 0x0265, /* h ɥ */
  732. 'i', 0x1d09, /* i ᴉ */
  733. 'j', 0x1e37, /* j ḷ */
  734. 'k', 0x029e, /* k ʞ */
  735. 'l', 0x0237, /* l ȷ */
  736. 'm', 0x026f, /* m ɯ */
  737. 'r', 0x0279, /* r ɹ */
  738. 't', 0x0287, /* t ʇ */
  739. 'v', 0x028c, /* v ʌ */
  740. 'w', 0x028d, /* w ʍ */
  741. 'y', 0x028e, /* y ʎ */
  742. /* Not perfect, but better than nothing */
  743. '"', 0x201e, /* " „ */
  744. /* Misc Unicode */
  745. 0x00e6, 0x1d02, /* æ ᴂ */
  746. 0x0153, 0x1d14, /* œ ᴔ */
  747. /* CP437 */
  748. 0x258c, 0x2590, /* ▌ ▐ */
  749. 0x2584, 0x2580, /* ▄ ▀ */
  750. 0x2596, 0x259d, /* ▖ ▝ */
  751. 0x2597, 0x2598, /* ▗ ▘ */
  752. 0x2599, 0x259c, /* ▙ ▜ */
  753. 0x259f, 0x259b, /* ▟ ▛ */
  754. /* Box drawing */
  755. 0x250c, 0x2518, /* ┌ ┘ */
  756. 0x2510, 0x2514, /* ┐ └ */
  757. 0x251c, 0x2524, /* ├ ┤ */
  758. 0x252c, 0x2534, /* ┬ ┴ */
  759. 0x250f, 0x251b, /* ┏ ┛ */
  760. 0x2513, 0x2517, /* ┓ ┗ */
  761. 0x2523, 0x252b, /* ┣ ┫ */
  762. 0x2533, 0x253b, /* ┳ ┻ */
  763. 0x2554, 0x255d, /* ╔ ╝ */
  764. 0x2557, 0x255a, /* ╗ ╚ */
  765. 0x2560, 0x2563, /* ╠ ╣ */
  766. 0x2566, 0x2569, /* ╦ ╩ */
  767. 0x2552, 0x255b, /* ╒ ╛ */
  768. 0x2555, 0x2558, /* ╕ ╘ */
  769. 0x255e, 0x2561, /* ╞ ╡ */
  770. 0x2564, 0x2567, /* ╤ ╧ */
  771. 0x2553, 0x255c, /* ╓ ╜ */
  772. 0x2556, 0x2559, /* ╖ ╙ */
  773. 0x255f, 0x2562, /* ╟ ╢ */
  774. 0x2565, 0x2568, /* ╥ ╨ */
  775. 0x2574, 0x2576, /* ╴ ╶ */
  776. 0x2575, 0x2577, /* ╵ ╷ */
  777. 0x2578, 0x257a, /* ╸ ╺ */
  778. 0x2579, 0x257b, /* ╹ ╻ */
  779. 0
  780. };
  781. for(i = 0; norotate[i]; i++)
  782. if(ch == norotate[i])
  783. return ch;
  784. for(i = 0; pairs[i]; i++)
  785. if(ch == pairs[i])
  786. return pairs[i ^ 1];
  787. return ch;
  788. }
  789. static uint32_t const leftright2[] =
  790. {
  791. /* ASCII */
  792. '/', '\\',
  793. '|', '-',
  794. '|', '_', /* This is all right because there was already a '|' before */
  795. /* ASCII-Unicode */
  796. '|', 0x203e, /* | ‾ */
  797. /* Misc Unicode */
  798. 0x2571, 0x2572, /* ╱ ╲ */
  799. /* Box drawing */
  800. 0x2500, 0x2502, /* ─ │ */
  801. 0x2501, 0x2503, /* ━ ┃ */
  802. 0x2550, 0x2551, /* ═ ║ */
  803. 0, 0
  804. };
  805. static uint32_t const leftright4[] =
  806. {
  807. /* ASCII */
  808. '<', 'v', '>', '^',
  809. ',', '.', '\'', '`',
  810. /* ASCII / Unicode */
  811. '(', 0x203f, ')', 0x2040, /* ( ‿ ) ⁀ */
  812. /* Misc Unicode */
  813. 0x256d, 0x2570, 0x256f, 0x256e, /* ╭ ╰ ╯ ╮ */
  814. /* CP437 */
  815. 0x258c, 0x2584, 0x2590, 0x2580, /* ▌ ▄ ▐ ▀ */
  816. 0x2596, 0x2597, 0x259d, 0x2598, /* ▖ ▗ ▝ ▘ */
  817. 0x2599, 0x259f, 0x259c, 0x259b, /* ▙ ▟ ▜ ▛ */
  818. /* Box drawing */
  819. 0x250c, 0x2514, 0x2518, 0x2510, /* ┌ └ ┘ ┐ */
  820. 0x250f, 0x2517, 0x251b, 0x2513, /* ┏ ┗ ┛ ┓ */
  821. 0x251c, 0x2534, 0x2524, 0x252c, /* ├ ┴ ┤ ┬ */
  822. 0x2523, 0x253b, 0x252b, 0x2533, /* ┣ ┻ ┫ ┳ */
  823. 0x2552, 0x2559, 0x255b, 0x2556, /* ╒ ╙ ╛ ╖ */
  824. 0x2553, 0x2558, 0x255c, 0x2555, /* ╓ ╘ ╜ ╕ */
  825. 0x2554, 0x255a, 0x255d, 0x2557, /* ╔ ╚ ╝ ╗ */
  826. 0x255e, 0x2568, 0x2561, 0x2565, /* ╞ ╨ ╡ ╥ */
  827. 0x255f, 0x2567, 0x2562, 0x2564, /* ╟ ╧ ╢ ╤ */
  828. 0x2560, 0x2569, 0x2563, 0x2566, /* ╠ ╩ ╣ ╦ */
  829. 0x2574, 0x2577, 0x2576, 0x2575, /* ╴ ╷ ╶ ╵ */
  830. 0x2578, 0x257b, 0x257a, 0x2579, /* ╸ ╻ ╺ ╹ */
  831. 0, 0, 0, 0
  832. };
  833. static uint32_t leftchar(uint32_t ch)
  834. {
  835. int i;
  836. for(i = 0; leftright2[i]; i++)
  837. if(ch == leftright2[i])
  838. return leftright2[(i & ~1) | ((i + 1) & 1)];
  839. for(i = 0; leftright4[i]; i++)
  840. if(ch == leftright4[i])
  841. return leftright4[(i & ~3) | ((i + 1) & 3)];
  842. return ch;
  843. }
  844. static uint32_t rightchar(uint32_t ch)
  845. {
  846. int i;
  847. for(i = 0; leftright2[i]; i++)
  848. if(ch == leftright2[i])
  849. return leftright2[(i & ~1) | ((i - 1) & 1)];
  850. for(i = 0; leftright4[i]; i++)
  851. if(ch == leftright4[i])
  852. return leftright4[(i & ~3) | ((i - 1) & 3)];
  853. return ch;
  854. }
  855. static uint32_t const leftright2x2[] =
  856. {
  857. /* ASCII / Unicode */
  858. '-', '-', 0x4e28, CUCUL_MAGIC_FULLWIDTH, /* -- 丨 */
  859. '|', '|', 0x2f06, CUCUL_MAGIC_FULLWIDTH, /* || ⼆ */
  860. /* Unicode */
  861. 0x2584, 0x2580, 0x2580, 0x2584, /* ▄▀ ▀▄ */
  862. 0, 0, 0, 0
  863. };
  864. static uint32_t const leftright2x4[] =
  865. {
  866. /* ASCII */
  867. ':', ' ', '.', '.', ' ', ':', '\'', '\'',
  868. /* ASCII / Unicode */
  869. ' ', '`', 0x00b4, ' ', 0x02ce, ' ', ' ', ',', /* ` ´ ˎ , */
  870. ' ', '`', '\'', ' ', '.', ' ', ' ', ',', /* fallback ASCII */
  871. '`', ' ', ',', ' ', ' ', 0x00b4, ' ', 0x02ce, /* ` , ˎ ´ */
  872. '`', ' ', ',', ' ', ' ', '.', ' ', '\'', /* fallback ASCII */
  873. '/', ' ', '-', 0x02ce, ' ', '/', '`', '-', /* / -ˎ / `- */
  874. '/', ' ', '-', '.', ' ', '/', '\'', '-', /* fallback ASCII */
  875. '\\', ' ', ',', '-', ' ', '\\', '-', 0x00b4, /* \ ,- \ -´ */
  876. '\\', ' ', '.', '-', ' ', '\\', '-', '\'', /* fallback ASCII */
  877. '\\', ' ', '_', ',', ' ', '\\', 0x00b4, 0x203e, /* \ _, \ ´‾ */
  878. '\\', '_', '_', '/', 0x203e, '\\', '/', 0x203e, /* \_ _/ ‾\ /‾ */
  879. '_', '\\', 0x203e, '/', '\\', 0x203e, '/', '_', /* _\ ‾/ \‾ /_ */
  880. '|', ' ', '_', '_', ' ', '|', 0x203e, 0x203e, /* | __ | ‾‾ */
  881. '_', '|', 0x203e, '|', '|', 0x203e, '|', '_', /* _| ‾| |‾ |_ */
  882. '|', '_', '_', '|', 0x203e, '|', '|', 0x203e, /* |_ _| ‾| |‾ */
  883. '_', ' ', ' ', 0x2577, ' ', 0x203e, 0x2575, ' ', /* _ ╷ ‾ ╵ */
  884. ' ', '_', ' ', 0x2575, 0x203e, ' ', 0x2577, ' ', /* _ ╵ ‾ ╷ */
  885. '.', '_', '.', 0x2575, 0x203e, '\'', 0x2577, '\'', /* ._ .╵ ‾' ╷' */
  886. '(', '_', 0x203f, '|', 0x203e, ')', '|', 0x2040, /* (_ ‿| ‾) |⁀ */
  887. '(', 0x203e, '|', 0x203f, '_', ')', 0x2040, '|', /* (‾ |‿ _) ⁀| */
  888. '\\', '/', 0xff1e, CUCUL_MAGIC_FULLWIDTH,
  889. '/', '\\', 0xff1c, CUCUL_MAGIC_FULLWIDTH, /* \/ > /\ < */
  890. ')', ' ', 0xfe35, CUCUL_MAGIC_FULLWIDTH,
  891. ' ', '(', 0xfe36, CUCUL_MAGIC_FULLWIDTH, /* ) ︵ ( ︶ */
  892. '}', ' ', 0xfe37, CUCUL_MAGIC_FULLWIDTH,
  893. ' ', '{', 0xfe38, CUCUL_MAGIC_FULLWIDTH, /* } ︷ { ︸ */
  894. /* Not perfect, but better than nothing */
  895. '(', ' ', 0x02ce, ',', ' ', ')', 0x00b4, '`', /* ( ˎ, ) ´` */
  896. ' ', 'v', '>', ' ', 0x028c, ' ', ' ', '<', /* v > ʌ < */
  897. ' ', 'V', '>', ' ', 0x039b, ' ', ' ', '<', /* V > Λ < */
  898. 'v', ' ', '>', ' ', ' ', 0x028c, ' ', '<', /* v > ʌ < */
  899. 'V', ' ', '>', ' ', ' ', 0x039b, ' ', '<', /* V > Λ < */
  900. '\\', '|', 0xff1e, CUCUL_MAGIC_FULLWIDTH,
  901. '|', '\\', 0xff1c, CUCUL_MAGIC_FULLWIDTH, /* \| > |\ < */
  902. '|', '/', 0xff1e, CUCUL_MAGIC_FULLWIDTH,
  903. '/', '|', 0xff1c, CUCUL_MAGIC_FULLWIDTH, /* |/ > /| < */
  904. /* Unicode */
  905. 0x2584, ' ', ' ', 0x2584, ' ', 0x2580, 0x2580, ' ', /* ▄ ▄ ▀ ▀ */
  906. 0x2588, ' ', 0x2584, 0x2584, ' ', 0x2588, 0x2580, 0x2580, /* █ ▄▄ █ ▀▀ */
  907. 0x2588, 0x2584, 0x2584, 0x2588,
  908. 0x2580, 0x2588, 0x2588, 0x2580, /* █▄ ▄█ ▀█ █▀ */
  909. 0, 0, 0, 0, 0, 0, 0, 0
  910. };
  911. static void leftpair(uint32_t pair[2])
  912. {
  913. int i;
  914. for(i = 0; leftright2x2[i]; i += 2)
  915. if(pair[0] == leftright2x2[i] && pair[1] == leftright2x2[i + 1])
  916. {
  917. pair[0] = leftright2x2[(i & ~3) | ((i + 2) & 3)];
  918. pair[1] = leftright2x2[((i & ~3) | ((i + 2) & 3)) + 1];
  919. return;
  920. }
  921. for(i = 0; leftright2x4[i]; i += 2)
  922. if(pair[0] == leftright2x4[i] && pair[1] == leftright2x4[i + 1])
  923. {
  924. pair[0] = leftright2x4[(i & ~7) | ((i + 2) & 7)];
  925. pair[1] = leftright2x4[((i & ~7) | ((i + 2) & 7)) + 1];
  926. return;
  927. }
  928. }
  929. static void rightpair(uint32_t pair[2])
  930. {
  931. int i;
  932. for(i = 0; leftright2x2[i]; i += 2)
  933. if(pair[0] == leftright2x2[i] && pair[1] == leftright2x2[i + 1])
  934. {
  935. pair[0] = leftright2x2[(i & ~3) | ((i - 2) & 3)];
  936. pair[1] = leftright2x2[((i & ~3) | ((i - 2) & 3)) + 1];
  937. return;
  938. }
  939. for(i = 0; leftright2x4[i]; i += 2)
  940. if(pair[0] == leftright2x4[i] && pair[1] == leftright2x4[i + 1])
  941. {
  942. pair[0] = leftright2x4[(i & ~7) | ((i - 2) & 7)];
  943. pair[1] = leftright2x4[((i & ~7) | ((i - 2) & 7)) + 1];
  944. return;
  945. }
  946. }