diff --git a/cucul/transform.c b/cucul/transform.c index 9b0f5bd..08133e6 100644 --- a/cucul/transform.c +++ b/cucul/transform.c @@ -229,12 +229,11 @@ int cucul_rotate_180(cucul_canvas_t *cv) * not guaranteed to be reversible at all. * * Note that the width of the canvas is divided by two and becomes the - * new height. Height is multiplied by two and becomes the new width. It - * is illegal to pass a canvas with an odd width to this function. + * new height. Height is multiplied by two and becomes the new width. If + * the original width is an odd number, the division is rounded up. * * If an error occurs, -1 is returned and \b errno is set accordingly: * - \c EBUSY The canvas is in use by a display driver and cannot be rotated. - * - \c EINVAL The canvas' width is odd. * - \c ENOMEM Not enough memory to allocate the new canvas size. If this * happens, the previous canvas handle is still valid. * @@ -244,7 +243,7 @@ int cucul_rotate_180(cucul_canvas_t *cv) int cucul_rotate_left(cucul_canvas_t *cv) { uint32_t *newchars, *newattrs; - unsigned int x, y, subwidth, subheight; + unsigned int x, y, w2, h2; if(cv->refcount) { @@ -252,46 +251,55 @@ int cucul_rotate_left(cucul_canvas_t *cv) return -1; } - if(cv->width & 1) - { - seterrno(EINVAL); - return -1; - } - /* Save the current frame shortcuts */ _cucul_save_frame_info(cv); - newchars = malloc(cv->width * cv->height * sizeof(uint32_t)); + w2 = (cv->width + 1) / 2; + h2 = cv->height; + + newchars = malloc(w2 * h2 * 2 * sizeof(uint32_t)); if(!newchars) + { + seterrno(ENOMEM); return -1; + } - newattrs = malloc(cv->width * cv->height * sizeof(uint32_t)); + newattrs = malloc(w2 * h2 * 2 * sizeof(uint32_t)); if(!newattrs) { free(newchars); + seterrno(ENOMEM); return -1; } - subwidth = cv->width / 2; - subheight = cv->height; - - for(y = 0; y < subheight; y++) + for(y = 0; y < h2; y++) { - for(x = 0; x < subwidth; x++) + for(x = 0; x < w2; x++) { uint32_t pair[2], attr1, attr2; - pair[0] = cv->chars[(subwidth * y + x) * 2]; - attr1 = cv->attrs[(subwidth * y + x) * 2]; - pair[1] = cv->chars[(subwidth * y + x) * 2 + 1]; - attr2 = cv->attrs[(subwidth * y + x) * 2 + 1]; + pair[0] = cv->chars[cv->width * y + x * 2]; + attr1 = cv->attrs[cv->width * y + x * 2]; + + if((cv->width & 1) && x == w2 - 1) + { + /* Special case: odd column */ + pair[1] = ' '; + attr2 = attr1; + } + else + { + pair[1] = cv->chars[cv->width * y + x * 2 + 1]; + attr2 = cv->attrs[cv->width * y + x * 2 + 1]; + } + leftpair(pair); - newchars[(subheight * (subwidth - 1 - x) + y) * 2] = pair[0]; - newattrs[(subheight * (subwidth - 1 - x) + y) * 2] = attr1; - newchars[(subheight * (subwidth - 1 - x) + y) * 2 + 1] = pair[1]; - newattrs[(subheight * (subwidth - 1 - x) + y) * 2 + 1] = attr2; + newchars[(h2 * (w2 - 1 - x) + y) * 2] = pair[0]; + newattrs[(h2 * (w2 - 1 - x) + y) * 2] = attr1; + newchars[(h2 * (w2 - 1 - x) + y) * 2 + 1] = pair[1]; + newattrs[(h2 * (w2 - 1 - x) + y) * 2 + 1] = attr2; } } @@ -310,7 +318,7 @@ int cucul_rotate_left(cucul_canvas_t *cv) cv->frames[cv->frame].handley = (cv->width - 1 - x) / 2; cv->frames[cv->frame].width = cv->height * 2; - cv->frames[cv->frame].height = cv->width / 2; + cv->frames[cv->frame].height = (cv->width + 1) / 2; cv->frames[cv->frame].chars = newchars; cv->frames[cv->frame].attrs = newattrs; @@ -331,12 +339,11 @@ int cucul_rotate_left(cucul_canvas_t *cv) * not guaranteed to be reversible at all. * * Note that the width of the canvas is divided by two and becomes the - * new height. Height is multiplied by two and becomes the new width. It - * is illegal to pass a canvas with an odd width to this function. + * new height. Height is multiplied by two and becomes the new width. If + * the original width is an odd number, the division is rounded up. * * If an error occurs, -1 is returned and \b errno is set accordingly: * - \c EBUSY The canvas is in use by a display driver and cannot be rotated. - * - \c EINVAL The canvas' width is odd. * - \c ENOMEM Not enough memory to allocate the new canvas size. If this * happens, the previous canvas handle is still valid. * @@ -346,7 +353,7 @@ int cucul_rotate_left(cucul_canvas_t *cv) int cucul_rotate_right(cucul_canvas_t *cv) { uint32_t *newchars, *newattrs; - unsigned int x, y, subwidth, subheight; + unsigned int x, y, w2, h2; if(cv->refcount) { @@ -354,46 +361,54 @@ int cucul_rotate_right(cucul_canvas_t *cv) return -1; } - if(cv->width & 1) - { - seterrno(EINVAL); - return -1; - } - /* Save the current frame shortcuts */ _cucul_save_frame_info(cv); - newchars = malloc(cv->width * cv->height * sizeof(uint32_t)); + w2 = (cv->width + 1) / 2; + h2 = cv->height; + + newchars = malloc(w2 * h2 * 2 * sizeof(uint32_t)); if(!newchars) + { + seterrno(ENOMEM); return -1; + } - newattrs = malloc(cv->width * cv->height * sizeof(uint32_t)); + newattrs = malloc(w2 * h2 * 2 * sizeof(uint32_t)); if(!newattrs) { free(newchars); + seterrno(ENOMEM); return -1; } - subwidth = cv->width / 2; - subheight = cv->height; - - for(y = 0; y < subheight; y++) + for(y = 0; y < h2; y++) { - for(x = 0; x < subwidth; x++) + for(x = 0; x < w2; x++) { uint32_t pair[2], attr1, attr2; - pair[0] = cv->chars[(subwidth * y + x) * 2]; - attr1 = cv->attrs[(subwidth * y + x) * 2]; - pair[1] = cv->chars[(subwidth * y + x) * 2 + 1]; - attr2 = cv->attrs[(subwidth * y + x) * 2 + 1]; + pair[0] = cv->chars[cv->width * y + x * 2]; + attr1 = cv->attrs[cv->width * y + x * 2]; + + if((cv->width & 1) && x == w2 - 1) + { + /* Special case: odd column */ + pair[1] = ' '; + attr2 = attr1; + } + else + { + pair[1] = cv->chars[cv->width * y + x * 2 + 1]; + attr2 = cv->attrs[cv->width * y + x * 2 + 1]; + } rightpair(pair); - newchars[(subheight * x + subheight - 1 - y) * 2] = pair[0]; - newattrs[(subheight * x + subheight - 1 - y) * 2] = attr1; - newchars[(subheight * x + subheight - 1 - y) * 2 + 1] = pair[1]; - newattrs[(subheight * x + subheight - 1 - y) * 2 + 1] = attr2; + newchars[(h2 * x + h2 - 1 - y) * 2] = pair[0]; + newattrs[(h2 * x + h2 - 1 - y) * 2] = attr1; + newchars[(h2 * x + h2 - 1 - y) * 2 + 1] = pair[1]; + newattrs[(h2 * x + h2 - 1 - y) * 2 + 1] = attr2; } } @@ -412,7 +427,7 @@ int cucul_rotate_right(cucul_canvas_t *cv) cv->frames[cv->frame].handley = x / 2; cv->frames[cv->frame].width = cv->height * 2; - cv->frames[cv->frame].height = cv->width / 2; + cv->frames[cv->frame].height = (cv->width + 1) / 2; cv->frames[cv->frame].chars = newchars; cv->frames[cv->frame].attrs = newattrs; @@ -458,12 +473,16 @@ int cucul_stretch_left(cucul_canvas_t *cv) newchars = malloc(cv->width * cv->height * sizeof(uint32_t)); if(!newchars) + { + seterrno(ENOMEM); return -1; + } newattrs = malloc(cv->width * cv->height * sizeof(uint32_t)); if(!newattrs) { free(newchars); + seterrno(ENOMEM); return -1; } @@ -967,6 +986,7 @@ static uint32_t const leftright2x2[] = { /* ASCII / Unicode */ '-', '-', 0x4e28, CUCUL_MAGIC_FULLWIDTH, /* -- 丨 */ + '|', '|', 0x2f06, CUCUL_MAGIC_FULLWIDTH, /* || ⼆ */ /* Unicode */ 0x2584, 0x2580, 0x2580, 0x2584, /* ▄▀ ▀▄ */ 0, 0, 0, 0 @@ -987,19 +1007,31 @@ static uint32_t const leftright2x4[] = '\\', ' ', '.', '-', ' ', '\\', '-', '\'', /* fallback ASCII */ '\\', ' ', '_', ',', ' ', '\\', 0x00b4, 0x203e, /* \ _, \ ´‾ */ '\\', '_', '_', '/', 0x203e, '\\', '/', 0x203e, /* \_ _/ ‾\ /‾ */ + '_', '\\', 0x203e, '/', '\\', 0x203e, '/', '_', /* _\ ‾/ \‾ /_ */ '|', ' ', '_', '_', ' ', '|', 0x203e, 0x203e, /* | __ | ‾‾ */ '_', '|', 0x203e, '|', '|', 0x203e, '|', '_', /* _| ‾| |‾ |_ */ '|', '_', '_', '|', 0x203e, '|', '|', 0x203e, /* |_ _| ‾| |‾ */ '_', ' ', ' ', 0x2577, ' ', 0x203e, 0x2575, ' ', /* _ ╷ ‾ ╵ */ ' ', '_', ' ', 0x2575, 0x203e, ' ', 0x2577, ' ', /* _ ╵ ‾ ╷ */ '.', '_', '.', 0x2575, 0x203e, '\'', 0x2577, '\'', /* ._ .╵ ‾' ╷' */ + '(', '_', 0x203f, '|', 0x203e, ')', '|', 0x2040, /* (_ ‿| ‾) |⁀ */ + '(', 0x203e, '|', 0x203f, '_', ')', 0x2040, '|', /* (‾ |‿ _) ⁀| */ '\\', '/', 0xff1e, CUCUL_MAGIC_FULLWIDTH, '/', '\\', 0xff1c, CUCUL_MAGIC_FULLWIDTH, /* \/ > /\ < */ + ')', ' ', 0xfe35, CUCUL_MAGIC_FULLWIDTH, + ' ', '(', 0xfe36, CUCUL_MAGIC_FULLWIDTH, /* ) ︵ ( ︶ */ + '}', ' ', 0xfe37, CUCUL_MAGIC_FULLWIDTH, + ' ', '{', 0xfe38, CUCUL_MAGIC_FULLWIDTH, /* } ︷ { ︸ */ /* Not perfect, but better than nothing */ '(', ' ', 0x02ce, ',', ' ', ')', 0x00b4, '`', /* ( ˎ, ) ´` */ - ')', ' ', ',', 0x02ce, ' ', '(', '`', 0x00b4, /* ) ,ˎ ( `´ */ + ' ', 'v', '>', ' ', 0x028c, ' ', ' ', '<', /* v > ʌ < */ ' ', 'V', '>', ' ', 0x039b, ' ', ' ', '<', /* V > Λ < */ + 'v', ' ', '>', ' ', ' ', 0x028c, ' ', '<', /* v > ʌ < */ 'V', ' ', '>', ' ', ' ', 0x039b, ' ', '<', /* V > Λ < */ + '\\', '|', 0xff1e, CUCUL_MAGIC_FULLWIDTH, + '|', '\\', 0xff1c, CUCUL_MAGIC_FULLWIDTH, /* \| > |\ < */ + '|', '/', 0xff1e, CUCUL_MAGIC_FULLWIDTH, + '/', '|', 0xff1c, CUCUL_MAGIC_FULLWIDTH, /* |/ > /| < */ /* Unicode */ 0x2584, ' ', ' ', 0x2584, ' ', 0x2580, 0x2580, ' ', /* ▄ ▄ ▀ ▀ */ 0x2588, ' ', 0x2584, 0x2584, ' ', 0x2588, 0x2580, 0x2580, /* █ ▄▄ █ ▀▀ */