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

Last change on this file since 4386 was 4386, checked in by Pascal Terjan, 10 years ago
  • Add few unicode charecters to the flip table
  • Property svn:keywords set to Id
File size: 36.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         0
795    };
796
797    static uint32_t const pairs[] =
798    {
799         /* ASCII */
800         '/', '\\',
801         'M', 'W',
802         ',', '`',
803         'b', 'p',
804         'd', 'q',
805         'p', 'q',
806         'f', 't',
807         '.', '\'',
808         /* ASCII-Unicode */
809         '_', 0x203e, /* _ ‾ */
810         '!', 0x00a1, /* ! ¡ */
811         'A', 0x2200, /* A ∀ */
812         'J', 0x1489, /* J ᒉ */
813         'L', 0x0413, /* L Г */
814         'N', 0x0418, /* N И */
815         'P', 0x042c, /* P Ь */
816         'R', 0x0281, /* R ʁ */
817         'S', 0x01a7, /* S Ƨ */
818         'U', 0x0548, /* U Ո */
819         'V', 0x039b, /* V Λ */
820         'Y', 0x2144, /* Y ⅄ */
821         'h', 0x03bc, /* h μ */
822         'i', 0x1d09, /* i ᴉ */
823         'j', 0x1e37, /* j ḷ */
824         'l', 0x0237, /* l ȷ */
825         'v', 0x028c, /* v ʌ */
826         'w', 0x028d, /* w ʍ */
827         'y', 0x03bb, /* y λ */
828         /* Not perfect, but better than nothing */
829         '"', 0x201e, /* " „ */
830         'm', 0x026f, /* m ɯ */
831         'n', 'u',
832         /* CP437 */
833         0x2584, 0x2580, /* ▄ ▀ */
834         0x2596, 0x2598, /* ▖ ▘ */
835         0x2597, 0x259d, /* ▗ ▝ */
836         0x2599, 0x259b, /* ▙ ▛ */
837         0x259f, 0x259c, /* ▟ ▜ */
838         0x259a, 0x259e, /* ▚ ▞ */
839         /* Box drawing */
840         0x250c, 0x2514, /* ┌ └ */
841         0x2510, 0x2518, /* ┐ ┘ */
842         0x252c, 0x2534, /* ┬ ┴ */
843         0x250f, 0x2517, /* ┏ ┗ */
844         0x2513, 0x251b, /* ┓ ┛ */
845         0x2533, 0x253b, /* ┳ ┻ */
846         0x2554, 0x255a, /* ╔ ╚ */
847         0x2557, 0x255d, /* ╗ ╝ */
848         0x2566, 0x2569, /* ╦ ╩ */
849         0x2552, 0x2558, /* ╒ ╘ */
850         0x2555, 0x255b, /* ╕ ╛ */
851         0x2564, 0x2567, /* ╤ ╧ */
852         0x2553, 0x2559, /* ╓ ╙ */
853         0x2556, 0x255c, /* ╖ ╜ */
854         0x2565, 0x2568, /* ╥ ╨ */
855         0x2575, 0x2577, /* ╵ ╷ */
856         0x2579, 0x257b, /* ╹ ╻ */
857         0
858    };
859
860    for(i = 0; noflop[i]; i++)
861        if(ch == noflop[i])
862            return ch;
863
864    for(i = 0; pairs[i]; i++)
865        if(ch == pairs[i])
866            return pairs[i ^ 1];
867
868    return ch;
869}
870
871static uint32_t rotatechar(uint32_t ch)
872{
873    int i;
874
875    static uint32_t const norotate[] =
876    {
877         /* ASCII */
878         ' ', '*', '+', '-', '/', '0', '8', ':', '=', 'H', 'I', 'N',
879         'O', 'S', 'X', 'Z', '\\', 'o', 's', 'x', 'z', '|',
880         /* Unicode */
881         0x2591, 0x2592, 0x2593, 0x2588, 0x259a, 0x259e, /* ░ ▒ ▓ █ ▚ ▞ */
882         0x2500, 0x2501, 0x2503, 0x2503, 0x253c, 0x254b, /* ─ ━ │ ┃ ┼ ╋ */
883         0x2550, 0x2551, 0x256c, /* ═ ║ ╬ */
884         0
885    };
886
887    static uint32_t const pairs[] =
888    {
889         /* ASCII */
890         '(', ')',
891         '<', '>',
892         '[', ']',
893         '{', '}',
894         '.', '\'',
895         '6', '9',
896         'M', 'W',
897         'b', 'q',
898         'd', 'p',
899         'n', 'u',
900         /* ASCII-Unicode */
901         '_', 0x203e, /* _ ‾ */
902         ',', 0x00b4, /* , ´ */
903         '`', 0x02ce, /* ` ˎ */
904         '&', 0x214b, /* & ⅋ */
905         '!', 0x00a1, /* ! ¡ */
906         '?', 0x00bf, /* ? ¿ */
907         'A', 0x2200, /* A ∀ */
908         'B', 0x10412,/* B 𐐒 */
909         'C', 0x03fd, /* C Ͻ */
910         'D', 0x15e1, /* D ᗡ */
911         'E', 0x018e, /* E Ǝ */
912         'F', 0x2132, /* F Ⅎ -- 0x07c3 looks better, but is RTL */
913         'G', 0x2141, /* G ⅁ */
914         'J', 0x148b, /* J ᒋ */
915         'L', 0x2142, /* L ⅂ */
916         'U', 0x0548, /* U Ո */
917         'V', 0x039b, /* V Λ */
918         'Y', 0x2144, /* Y ⅄ */
919         'a', 0x0250, /* a ɐ */
920         'c', 0x0254, /* c ɔ */
921         'e', 0x01dd, /* e ǝ */
922         'f', 0x025f, /* f ɟ */
923         'g', 0x1d77, /* g ᵷ */
924         'h', 0x0265, /* h ɥ */
925         'i', 0x1d09, /* i ᴉ */
926         'j', 0x1e37, /* j ḷ */
927         'k', 0x029e, /* k ʞ */
928         'l', 0x0237, /* l ȷ */
929         'm', 0x026f, /* m ɯ */
930         'r', 0x0279, /* r ɹ */
931         't', 0x0287, /* t ʇ */
932         'v', 0x028c, /* v ʌ */
933         'w', 0x028d, /* w ʍ */
934         'y', 0x028e, /* y ʎ */
935         /* Unicode-ASCII to match third-party software */
936         0x0183, 'g', /* ƃ g */
937         0x0259, 'e', /* ə e */
938         0x027e, 'j', /* ɾ j */
939         0x02d9, '.', /* ˙ . */
940         0x05df, 'l', /* ן l */
941         /* Not perfect, but better than nothing */
942         '"', 0x201e, /* " „ */
943         /* Misc Unicode */
944         0x00e6, 0x1d02, /* æ ᴂ */
945         0x0153, 0x1d14, /* œ ᴔ */
946         0x03b5, 0x025c, /* ε ɜ */
947         0x025b, 0x025c, /* ɛ ɜ */
948         /* CP437 */
949         0x258c, 0x2590, /* ▌ ▐ */
950         0x2584, 0x2580, /* ▄ ▀ */
951         0x2596, 0x259d, /* ▖ ▝ */
952         0x2597, 0x2598, /* ▗ ▘ */
953         0x2599, 0x259c, /* ▙ ▜ */
954         0x259f, 0x259b, /* ▟ ▛ */
955         /* Box drawing */
956         0x250c, 0x2518, /* ┌ ┘ */
957         0x2510, 0x2514, /* ┐ └ */
958         0x251c, 0x2524, /* ├ ┤ */
959         0x252c, 0x2534, /* ┬ ┴ */
960         0x250f, 0x251b, /* ┏ ┛ */
961         0x2513, 0x2517, /* ┓ ┗ */
962         0x2523, 0x252b, /* ┣ ┫ */
963         0x2533, 0x253b, /* ┳ ┻ */
964         0x2554, 0x255d, /* ╔ ╝ */
965         0x2557, 0x255a, /* ╗ ╚ */
966         0x2560, 0x2563, /* ╠ ╣ */
967         0x2566, 0x2569, /* ╦ ╩ */
968         0x2552, 0x255b, /* ╒ ╛ */
969         0x2555, 0x2558, /* ╕ ╘ */
970         0x255e, 0x2561, /* ╞ ╡ */
971         0x2564, 0x2567, /* ╤ ╧ */
972         0x2553, 0x255c, /* ╓ ╜ */
973         0x2556, 0x2559, /* ╖ ╙ */
974         0x255f, 0x2562, /* ╟ ╢ */
975         0x2565, 0x2568, /* ╥ ╨ */
976         0x2574, 0x2576, /* ╴ ╶ */
977         0x2575, 0x2577, /* ╵ ╷ */
978         0x2578, 0x257a, /* ╸ ╺ */
979         0x2579, 0x257b, /* ╹ ╻ */
980         0
981    };
982
983    for(i = 0; norotate[i]; i++)
984        if(ch == norotate[i])
985            return ch;
986
987    for(i = 0; pairs[i]; i++)
988        if(ch == pairs[i])
989            return pairs[i ^ 1];
990
991    return ch;
992}
993
994static uint32_t const leftright2[] =
995{
996    /* ASCII */
997    '/', '\\',
998    '|', '-',
999    '|', '_', /* This is all right because there was already a '|' before */
1000    /* ASCII-Unicode */
1001    '|', 0x203e, /* | ‾ */
1002    /* Misc Unicode */
1003    0x2571, 0x2572, /* ╱ ╲ */
1004    /* Box drawing */
1005    0x2500, 0x2502, /* ─ │ */
1006    0x2501, 0x2503, /* ━ ┃ */
1007    0x2550, 0x2551, /* ═ ║ */
1008    0, 0
1009};
1010
1011static uint32_t const leftright4[] =
1012{
1013    /* ASCII */
1014    '<', 'v', '>', '^',
1015    ',', '.', '\'', '`',
1016    /* ASCII / Unicode */
1017    '(', 0x203f, ')', 0x2040,       /* ( ‿ ) ⁀ */
1018    /* Misc Unicode */
1019    0x256d, 0x2570, 0x256f, 0x256e, /* ╭ ╰ ╯ ╮ */
1020    /* CP437 */
1021    0x258c, 0x2584, 0x2590, 0x2580, /* ▌ ▄ ▐ ▀ */
1022    0x2596, 0x2597, 0x259d, 0x2598, /* ▖ ▗ ▝ ▘ */
1023    0x2599, 0x259f, 0x259c, 0x259b, /* ▙ ▟ ▜ ▛ */
1024    /* Box drawing */
1025    0x250c, 0x2514, 0x2518, 0x2510, /* ┌ └ ┘ ┐ */
1026    0x250f, 0x2517, 0x251b, 0x2513, /* ┏ ┗ ┛ ┓ */
1027    0x251c, 0x2534, 0x2524, 0x252c, /* ├ ┴ ┤ ┬ */
1028    0x2523, 0x253b, 0x252b, 0x2533, /* ┣ ┻ ┫ ┳ */
1029    0x2552, 0x2559, 0x255b, 0x2556, /* ╒ ╙ ╛ ╖ */
1030    0x2553, 0x2558, 0x255c, 0x2555, /* ╓ ╘ ╜ ╕ */
1031    0x2554, 0x255a, 0x255d, 0x2557, /* ╔ ╚ ╝ ╗ */
1032    0x255e, 0x2568, 0x2561, 0x2565, /* ╞ ╨ ╡ ╥ */
1033    0x255f, 0x2567, 0x2562, 0x2564, /* ╟ ╧ ╢ ╤ */
1034    0x2560, 0x2569, 0x2563, 0x2566, /* ╠ ╩ ╣ ╦ */
1035    0x2574, 0x2577, 0x2576, 0x2575, /* ╴ ╷ ╶ ╵ */
1036    0x2578, 0x257b, 0x257a, 0x2579, /* ╸ ╻ ╺ ╹ */
1037    0, 0, 0, 0
1038};
1039
1040static uint32_t leftchar(uint32_t ch)
1041{
1042    int i;
1043
1044    for(i = 0; leftright2[i]; i++)
1045        if(ch == leftright2[i])
1046            return leftright2[(i & ~1) | ((i + 1) & 1)];
1047
1048    for(i = 0; leftright4[i]; i++)
1049        if(ch == leftright4[i])
1050            return leftright4[(i & ~3) | ((i + 1) & 3)];
1051
1052    return ch;
1053}
1054
1055static uint32_t rightchar(uint32_t ch)
1056{
1057    int i;
1058
1059    for(i = 0; leftright2[i]; i++)
1060        if(ch == leftright2[i])
1061            return leftright2[(i & ~1) | ((i - 1) & 1)];
1062
1063    for(i = 0; leftright4[i]; i++)
1064        if(ch == leftright4[i])
1065            return leftright4[(i & ~3) | ((i - 1) & 3)];
1066
1067    return ch;
1068}
1069
1070static uint32_t const leftright2x2[] =
1071{
1072    /* ASCII / Unicode */
1073    '-', '-', 0x4e28, CACA_MAGIC_FULLWIDTH, /* -- 丨 */
1074    '|', '|', 0x2f06, CACA_MAGIC_FULLWIDTH, /* || ⼆ */
1075    /* Unicode */
1076    0x2584, 0x2580, 0x2580, 0x2584, /* ▄▀ ▀▄ */
1077    0, 0, 0, 0
1078};
1079
1080static uint32_t const leftright2x4[] =
1081{
1082    /* ASCII */
1083    ':', ' ', '.', '.', ' ', ':', '\'', '\'',
1084    /* ASCII / Unicode */
1085    ' ', '`', 0x00b4, ' ', 0x02ce, ' ', ' ', ',',      /*  ` ´  ˎ   , */
1086    ' ', '`', '\'',   ' ', '.',    ' ', ' ', ',',      /* fallback ASCII */
1087    '`', ' ', ',', ' ', ' ', 0x00b4, ' ', 0x02ce,      /*  ` ,   ˎ  ´ */
1088    '`', ' ', ',', ' ', ' ', '.',    ' ', '\'',        /* fallback ASCII */
1089    '/', ' ', '-', 0x02ce, ' ', '/', '`', '-',         /* /  -ˎ  / `- */
1090    '/', ' ', '-', '.',    ' ', '/', '\'', '-',        /* fallback ASCII */
1091    '\\', ' ', ',', '-', ' ', '\\', '-', 0x00b4,       /* \  ,-  \ -´ */
1092    '\\', ' ', '.', '-', ' ', '\\', '-', '\'',         /* fallback ASCII */
1093    '\\', ' ', '_', ',', ' ', '\\', 0x00b4, 0x203e,    /* \  _,  \ ´‾ */
1094    '\\', '_', '_', '/', 0x203e, '\\', '/', 0x203e,    /* \_ _/ ‾\ /‾ */
1095    '_', '\\', 0x203e, '/', '\\', 0x203e, '/', '_',    /* _\ ‾/ \‾ /_ */
1096    '|', ' ', '_', '_', ' ', '|', 0x203e, 0x203e,      /* |  __  | ‾‾ */
1097    '_', '|', 0x203e, '|', '|', 0x203e, '|', '_',      /* _| ‾| |‾ |_ */
1098    '|', '_', '_', '|', 0x203e, '|', '|', 0x203e,      /* |_ _| ‾| |‾ */
1099    '_', ' ', ' ', 0x2577, ' ', 0x203e, 0x2575, ' ',   /* _   ╷  ‾ ╵  */
1100    ' ', '_', ' ', 0x2575, 0x203e, ' ', 0x2577, ' ',   /*  _  ╵ ‾  ╷  */
1101    '.', '_', '.', 0x2575, 0x203e, '\'', 0x2577, '\'', /* ._ .╵ ‾' ╷' */
1102    '(', '_', 0x203f, '|', 0x203e, ')', '|', 0x2040,   /* (_ ‿| ‾) |⁀ */
1103    '(', 0x203e, '|', 0x203f, '_', ')', 0x2040, '|',   /* (‾ |‿ _) ⁀| */
1104    '\\', '/', 0xff1e, CACA_MAGIC_FULLWIDTH,
1105            '/', '\\', 0xff1c, CACA_MAGIC_FULLWIDTH,  /* \/ > /\ < */
1106    ')', ' ', 0xfe35, CACA_MAGIC_FULLWIDTH,
1107            ' ', '(', 0xfe36, CACA_MAGIC_FULLWIDTH,   /* )  ︵  ( ︶ */
1108    '}', ' ', 0xfe37, CACA_MAGIC_FULLWIDTH,
1109            ' ', '{', 0xfe38, CACA_MAGIC_FULLWIDTH,   /* }  ︷  { ︸ */
1110    /* Not perfect, but better than nothing */
1111    '(', ' ', 0x02ce, ',', ' ', ')', 0x00b4, '`',      /* (  ˎ,  ) ´` */
1112    ' ', 'v', '>', ' ', 0x028c, ' ', ' ', '<',         /*  v >  ʌ   < */
1113    ' ', 'V', '>', ' ', 0x039b, ' ', ' ', '<',         /*  V >  Λ   < */
1114    'v', ' ', '>', ' ', ' ', 0x028c, ' ', '<',         /* v  >   ʌ  < */
1115    'V', ' ', '>', ' ', ' ', 0x039b, ' ', '<',         /* V  >   Λ  < */
1116    '\\', '|', 0xff1e, CACA_MAGIC_FULLWIDTH,
1117            '|', '\\', 0xff1c, CACA_MAGIC_FULLWIDTH,  /* \| > |\ < */
1118    '|', '/', 0xff1e, CACA_MAGIC_FULLWIDTH,
1119            '/', '|', 0xff1c, CACA_MAGIC_FULLWIDTH,   /* |/ > /| < */
1120    /* Unicode */
1121    0x2584, ' ', ' ', 0x2584, ' ', 0x2580, 0x2580, ' ',       /* ▄   ▄  ▀ ▀  */
1122    0x2588, ' ', 0x2584, 0x2584, ' ', 0x2588, 0x2580, 0x2580, /* █  ▄▄  █ ▀▀ */
1123    0x2588, 0x2584, 0x2584, 0x2588,
1124            0x2580, 0x2588, 0x2588, 0x2580,                   /* █▄ ▄█ ▀█ █▀ */
1125    /* TODO: Braille */
1126    /* Not perfect, but better than nothing */
1127    0x2591, ' ', 0x28e4, 0x28e4, ' ', 0x2591, 0x281b, 0x281b, /* ░  ⣤⣤  ░ ⠛⠛ */
1128    0x2592, ' ', 0x28f6, 0x28f6, ' ', 0x2592, 0x283f, 0x283f, /* ▒  ⣶⣶  ▒ ⠿⠿ */
1129    0, 0, 0, 0, 0, 0, 0, 0
1130};
1131
1132static void leftpair(uint32_t pair[2])
1133{
1134    int i;
1135
1136    for(i = 0; leftright2x2[i]; i += 2)
1137        if(pair[0] == leftright2x2[i] && pair[1] == leftright2x2[i + 1])
1138        {
1139            pair[0] = leftright2x2[(i & ~3) | ((i + 2) & 3)];
1140            pair[1] = leftright2x2[((i & ~3) | ((i + 2) & 3)) + 1];
1141            return;
1142        }
1143
1144    for(i = 0; leftright2x4[i]; i += 2)
1145        if(pair[0] == leftright2x4[i] && pair[1] == leftright2x4[i + 1])
1146        {
1147            pair[0] = leftright2x4[(i & ~7) | ((i + 2) & 7)];
1148            pair[1] = leftright2x4[((i & ~7) | ((i + 2) & 7)) + 1];
1149            return;
1150        }
1151}
1152
1153static void rightpair(uint32_t pair[2])
1154{
1155    int i;
1156
1157    for(i = 0; leftright2x2[i]; i += 2)
1158        if(pair[0] == leftright2x2[i] && pair[1] == leftright2x2[i + 1])
1159        {
1160            pair[0] = leftright2x2[(i & ~3) | ((i - 2) & 3)];
1161            pair[1] = leftright2x2[((i & ~3) | ((i - 2) & 3)) + 1];
1162            return;
1163        }
1164
1165    for(i = 0; leftright2x4[i]; i += 2)
1166        if(pair[0] == leftright2x4[i] && pair[1] == leftright2x4[i + 1])
1167        {
1168            pair[0] = leftright2x4[(i & ~7) | ((i - 2) & 7)];
1169            pair[1] = leftright2x4[((i & ~7) | ((i - 2) & 7)) + 1];
1170            return;
1171        }
1172}
1173
1174/*
1175 * XXX: The following functions are aliases.
1176 */
1177
1178int cucul_invert(cucul_canvas_t *) CACA_ALIAS(caca_invert);
1179int cucul_flip(cucul_canvas_t *) CACA_ALIAS(caca_flip);
1180int cucul_flop(cucul_canvas_t *) CACA_ALIAS(caca_flop);
1181int cucul_rotate_180(cucul_canvas_t *) CACA_ALIAS(caca_rotate_180);
1182int cucul_rotate_left(cucul_canvas_t *) CACA_ALIAS(caca_rotate_left);
1183int cucul_rotate_right(cucul_canvas_t *) CACA_ALIAS(caca_rotate_right);
1184int cucul_stretch_left(cucul_canvas_t *) CACA_ALIAS(caca_stretch_left);
1185int cucul_stretch_right(cucul_canvas_t *) CACA_ALIAS(caca_stretch_right);
1186
Note: See TracBrowser for help on using the repository browser.