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.

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