Переглянути джерело

* Support for fullwidth (= double width) Unicode characters.

tags/v0.99.beta14
Sam Hocevar sam 18 роки тому
джерело
коміт
b45eea0b39
2 змінених файлів з 72 додано та 34 видалено
  1. +70
    -34
      cucul/canvas.c
  2. +2
    -0
      cucul/cucul_internals.h

+ 70
- 34
cucul/canvas.c Переглянути файл

@@ -47,10 +47,14 @@
* coordinates, using the default foreground and background values.
*
* If the coordinates are outside the canvas boundaries, nothing is printed.
* If the character value is a non-printable character or is outside the
* UTF-32 range, it is replaced with a space. To print a sequence of bytes
* forming an UTF-8 character instead of an UTF-32 character, use the
* cucul_putstr() function instead.
* If a fullwidth Unicode character gets overwritten, its remaining parts
* are replaced with spaces. If the canvas' boundaries would split the
* fullwidth character in two, a space is printed instead.
*
* The behaviour when printing non-printable characters or invalid UTF-32
* characters is undefined. To print a sequence of bytes forming an UTF-8
* character instead of an UTF-32 character, use the cucul_putstr() function
* instead.
*
* This function never fails.
*
@@ -62,14 +66,57 @@
*/
int cucul_putchar(cucul_canvas_t *cv, int x, int y, unsigned long int ch)
{
if(x < 0 || x >= (int)cv->width || y < 0 || y >= (int)cv->height)
uint32_t *curchar, *curattr, attr;
int fullwidth;

if(!ch || x >= (int)cv->width || y < 0 || y >= (int)cv->height)
return 0;

if(ch < 0x20)
ch = 0x20;
fullwidth = cucul_utf32_is_fullwidth(ch);

cv->chars[x + y * cv->width] = ch;
cv->attr[x + y * cv->width] = (cv->bgcolor << 16) | cv->fgcolor;
if(x == -1 && fullwidth)
{
x = 0;
ch = ' ';
fullwidth = 0;
}
else if(x < 0)
return 0;

curchar = cv->chars + x + y * cv->width;
curattr = cv->attr + x + y * cv->width;
attr = (cv->bgcolor << 16) | cv->fgcolor;

/* When overwriting the right part of a fullwidth character,
* replace its left part with a space. */
if(x && curchar[0] == MAGIC_FULLWIDTH)
curchar[-1] = ' ';

if(fullwidth)
{
if(x + 1 == (int)cv->width)
ch = ' ';
else
{
/* When overwriting the left part of a fullwidth character,
* replace its right part with a space. */
if(x + 2 < (int)cv->width && curchar[2] == MAGIC_FULLWIDTH)
curchar[2] = ' ';

curchar[1] = MAGIC_FULLWIDTH;
curattr[1] = attr;
}
}
else
{
/* When overwriting the left part of a fullwidth character,
* replace its right part with a space. */
if(x + 1 != (int)cv->width && curchar[1] == MAGIC_FULLWIDTH)
curchar[1] = ' ';
}

curchar[0] = ch;
curattr[0] = attr;

return 0;
}
@@ -82,7 +129,7 @@ int cucul_putchar(cucul_canvas_t *cv, int x, int y, unsigned long int ch)
* as a UTF-32 value.
*
* If the coordinates are outside the canvas boundaries, a space (0x20)
* is returned.
* is returned. FIXME: explain MAGIC_FULLWIDTH
*
* This function never fails.
*
@@ -95,7 +142,7 @@ int cucul_putchar(cucul_canvas_t *cv, int x, int y, unsigned long int ch)
unsigned long int cucul_getchar(cucul_canvas_t *cv, int x, int y)
{
if(x < 0 || x >= (int)cv->width || y < 0 || y >= (int)cv->height)
return (unsigned char)' ';
return ' ';

return (unsigned long int)cv->chars[x + y * cv->width];
}
@@ -107,6 +154,9 @@ unsigned long int cucul_getchar(cucul_canvas_t *cv, int x, int y)
* the canvas boundaries (eg. a negative Y coordinate) and the string will
* be cropped accordingly if it is too long.
*
* See cucul_putchar() for more information on how fullwidth characters
* are handled when overwriting each other or at the canvas' boundaries.
*
* This function never fails.
*
* \param cv A handle to the libcucul canvas.
@@ -117,36 +167,23 @@ unsigned long int cucul_getchar(cucul_canvas_t *cv, int x, int y)
*/
int cucul_putstr(cucul_canvas_t *cv, int x, int y, char const *s)
{
uint32_t *chars, *attr;
unsigned int len;
unsigned int read;

if(y < 0 || y >= (int)cv->height || x >= (int)cv->width)
return 0;

len = _cucul_strlen_utf8(s);

if(x < 0)
while(*s && x < -1)
{
if(len < (unsigned int)-x)
return 0;
len -= -x;
s = _cucul_skip_utf8(s, -x);
x = 0;
x += cucul_utf32_is_fullwidth(cucul_utf8_to_utf32(s, &read)) ? 2 : 1;
s += read;
}

chars = cv->chars + x + y * cv->width;
attr = cv->attr + x + y * cv->width;

if(x + len >= cv->width)
len = cv->width - x;

while(len)
while(*s && x < (int)cv->width)
{
*chars++ = cucul_utf8_to_utf32(s, NULL);
*attr++ = (cv->bgcolor << 16) | cv->fgcolor;

s = _cucul_skip_utf8(s, 1);
len--;
uint32_t ch = cucul_utf8_to_utf32(s, &read);
cucul_putchar(cv, x, y, ch);
x += cucul_utf32_is_fullwidth(ch) ? 2 : 1;
s += read;
}

return 0;
@@ -212,7 +249,6 @@ int cucul_clear_canvas(cucul_canvas_t *cv)
uint32_t color = (cv->bgcolor << 16) | cv->fgcolor;
unsigned int n;

/* We could use SLsmg_cls() etc., but drawing empty lines is much faster */
for(n = cv->width * cv->height; n--; )
{
cv->chars[n] = (uint32_t)' ';


+ 2
- 0
cucul/cucul_internals.h Переглянути файл

@@ -18,6 +18,8 @@
# include <inttypes.h>
#endif

#define MAGIC_FULLWIDTH 0x00000000

struct cucul_canvas
{
/* Canvas size */


Завантаження…
Відмінити
Зберегти