Fix doublewidth character handling

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2010-03-16 21:29:15 +01:00
parent 2b5af23fa5
commit 6c363dfd54
6 changed files with 121 additions and 17 deletions

View file

@ -259,7 +259,13 @@ ascii.bitmaps: $(FONT_SOURCE) grub-mkfont
ascii.h: ascii.bitmaps grub-bin2h
$(builddir)/grub-bin2h ascii_bitmaps < $< > $@
TARGET_CFLAGS += -DUSE_ASCII_FAILBACK=1
widthspec.bin: $(FONT_SOURCE) grub-mkfont
$(builddir)/grub-mkfont --width-spec -o $@ $(FONT_SOURCE)
widthspec.h: widthspec.bin grub-bin2h
$(builddir)/grub-bin2h widthspec < $< > $@
TARGET_CFLAGS += -DUSE_ASCII_FAILBACK=1 -DHAVE_UNIFONT_WIDTHSPEC=1
endif
endif

View file

@ -640,6 +640,10 @@ normal_mod_SOURCES = normal/main.c normal/cmdline.c normal/dyncmd.c \
normal/menu_entry.c normal/menu_text.c normal/charset.c \
normal/misc.c normal/crypto.c normal/term.c normal/context.c \
unidata.c
ifneq (, $(FONT_SOURCE))
normal/charset.c_SOURCES += widthspec.h
endif
normal_mod_CFLAGS = $(COMMON_CFLAGS)
normal_mod_LDFLAGS = $(COMMON_LDFLAGS)

View file

@ -380,12 +380,36 @@ grub_term_cls (struct grub_term_output *term)
}
}
#ifdef HAVE_UNIFONT_WIDTHSPEC
grub_ssize_t
grub_unicode_estimate_width (const struct grub_unicode_glyph *c);
#else
static inline grub_ssize_t
grub_unicode_estimate_width (const struct grub_unicode_glyph *c __attribute__ ((unused)))
{
if (grub_unicode_get_comb_type (c->base))
return 0;
return 1;
}
#endif
static inline grub_ssize_t
grub_term_getcharwidth (struct grub_term_output *term,
const struct grub_unicode_glyph *c)
{
if (term->getcharwidth)
return term->getcharwidth (c);
else if (((term->flags & GRUB_TERM_CODE_TYPE_MASK)
== GRUB_TERM_CODE_TYPE_UTF8_LOGICAL)
|| ((term->flags & GRUB_TERM_CODE_TYPE_MASK)
== GRUB_TERM_CODE_TYPE_UTF8_VISUAL)
|| ((term->flags & GRUB_TERM_CODE_TYPE_MASK)
== GRUB_TERM_CODE_TYPE_VISUAL_GLYPHS))
return grub_unicode_estimate_width (c);
else
return 1;
}

View file

@ -30,6 +30,10 @@
#include <grub/term.h>
#include <grub/normal.h>
#ifdef HAVE_UNIFONT_WIDTHSPEC
#include "widthspec.h"
#endif
grub_ssize_t
grub_utf8_to_utf16 (grub_uint16_t *dest, grub_size_t destsize,
const grub_uint8_t *src, grub_size_t srcsize,
@ -465,6 +469,21 @@ grub_unicode_get_comb_type (grub_uint32_t c)
return GRUB_UNICODE_COMB_NONE;
}
#ifdef HAVE_UNIFONT_WIDTHSPEC
grub_ssize_t
grub_unicode_estimate_width (const struct grub_unicode_glyph *c)
{
if (grub_unicode_get_comb_type (c->base))
return 0;
if (widthspec[c->base >> 3] & (1 << (c->base & 7)))
return 2;
else
return 1;
}
#endif
grub_size_t
grub_unicode_aglomerate_comb (const grub_uint32_t *in, grub_size_t inlen,
struct grub_unicode_glyph *out)
@ -1098,7 +1117,7 @@ putglyph (const struct grub_unicode_glyph *c, struct grub_term_output *term)
== GRUB_TERM_CODE_TYPE_UTF8_VISUAL)
{
int i;
c2.estimated_width = 1;
c2.estimated_width = grub_term_getcharwidth (term, c);
for (i = -1; i < (int) c->ncomb; i++)
{
grub_uint8_t u8[20], *ptr;
@ -1192,8 +1211,15 @@ grub_print_ucs4 (const grub_uint32_t * str,
grub_ssize_t visual_len;
struct grub_unicode_glyph *visual;
struct grub_unicode_glyph *visual_ptr;
auto grub_ssize_t getcharwidth (const struct grub_unicode_glyph *c);
grub_ssize_t getcharwidth (const struct grub_unicode_glyph *c)
{
return grub_term_getcharwidth (term, c);
}
visual_len = grub_bidi_logical_to_visual (str, last_position - str,
&visual, term->getcharwidth,
&visual, getcharwidth,
max_width, startwidth);
if (visual_len < 0)
{
@ -1231,7 +1257,7 @@ grub_print_ucs4 (const grub_uint32_t * str,
.combining = 0
};
c.base = *ptr;
line_width += last_width = term->getcharwidth (&c);
line_width += last_width = grub_term_getcharwidth (term, &c);
}
if (*ptr == ' ')
@ -1279,7 +1305,15 @@ grub_print_ucs4 (const grub_uint32_t * str,
{
const grub_uint32_t *ptr2;
for (ptr2 = line_start; ptr2 < last_position; ptr2++)
grub_putcode (*ptr2, term);
{
/* Skip combining characters on non-UTF8 terminals. */
if ((term->flags & GRUB_TERM_CODE_TYPE_MASK)
!= GRUB_TERM_CODE_TYPE_UTF8_LOGICAL
&& grub_unicode_get_comb_type (*ptr2)
!= GRUB_UNICODE_COMB_NONE)
continue;
putcode_real (*ptr2, term);
}
}
}
}

View file

@ -364,12 +364,6 @@ grub_serial_putchar (const struct grub_unicode_glyph *c)
serial_hw_put (c->base);
}
static grub_ssize_t
grub_serial_getcharwidth (const struct grub_unicode_glyph *c __attribute__ ((unused)))
{
return 1;
}
static grub_uint16_t
grub_serial_getwh (void)
{
@ -449,7 +443,6 @@ static struct grub_term_output grub_serial_term_output =
{
.name = "serial",
.putchar = grub_serial_putchar,
.getcharwidth = grub_serial_getcharwidth,
.getwh = grub_serial_getwh,
.getxy = grub_serial_getxy,
.gotoxy = grub_serial_gotoxy,

View file

@ -53,7 +53,8 @@ struct grub_glyph_info
enum file_formats
{
PF2,
ASCII_BITMAPS
ASCII_BITMAPS,
WIDTH_SPEC
};
#define GRUB_FONT_FLAG_BOLD 1
@ -95,6 +96,7 @@ static struct option options[] =
{"version", no_argument, 0, 'V'},
{"verbose", no_argument, 0, 'v'},
{"ascii-bitmaps", no_argument, 0, 0x102},
{"width-spec", no_argument, 0, 0x103},
{0, 0, 0, 0}
};
@ -111,6 +113,7 @@ Usage: %s [OPTIONS] FONT_FILES\n\
\nOptions:\n\
-o, --output=FILE_NAME set output file name\n\
--ascii-bitmaps save only the ASCII bitmaps\n\
--width-spec create width summary file\n\
-i, --index=N set face index\n\
-r, --range=A-B[,C-D] set font range\n\
-n, --name=S set font family name\n\
@ -380,6 +383,32 @@ write_font_ascii_bitmap (struct grub_font_info *font_info, char *output_file)
fclose (file);
}
void
write_font_width_spec (struct grub_font_info *font_info, char *output_file)
{
FILE *file;
struct grub_glyph_info *glyph;
grub_uint8_t *out;
grub_uint8_t *rle;
int rle_size;
int i, j;
out = xmalloc (8192);
memset (out, 0, 8192);
file = fopen (output_file, "wb");
if (! file)
grub_util_error ("Can\'t write to file %s.", output_file);
for (glyph = font_info->glyph; glyph; glyph = glyph->next)
if (glyph->width > 12)
out[glyph->char_code >> 3] |= (1 << (glyph->char_code & 7));
fwrite (out, 8192, 1, file);
fclose (file);
free (out);
}
void
write_font_pf2 (struct grub_font_info *font_info, char *output_file)
{
@ -648,6 +677,10 @@ main (int argc, char *argv[])
file_format = ASCII_BITMAPS;
break;
case 0x103:
file_format = WIDTH_SPEC;
break;
default:
usage (1);
break;
@ -712,10 +745,20 @@ main (int argc, char *argv[])
FT_Done_FreeType (ft_lib);
if (file_format == PF2)
write_font_pf2 (&font_info, output_file);
else if (file_format == ASCII_BITMAPS)
write_font_ascii_bitmap (&font_info, output_file);
switch (file_format)
{
case PF2:
write_font_pf2 (&font_info, output_file);
break;
case ASCII_BITMAPS:
write_font_ascii_bitmap (&font_info, output_file);
break;
case WIDTH_SPEC:
write_font_width_spec (&font_info, output_file);
break;
}
if (font_verbosity > 1)
print_glyphs (&font_info);