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 години
преди 15 години
преди 16 години
преди 15 години
преди 17 години
преди 17 години
преди 17 години
преди 17 години
преди 17 години
преди 17 години
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160
  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);