source: libcaca/trunk/caca/transform.c @ 4387

Last change on this file since 4387 was 4387, checked in by Sam Hocevar, 10 years ago

Add new Unicode characters to other transformation routines.

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