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.
 
 
 
 
 
 

1122 lines
34 KiB

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