Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 
 
 

1161 lignes
35 KiB

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