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 ascii.h: ascii.bitmaps grub-bin2h
$(builddir)/grub-bin2h ascii_bitmaps < $< > $@ $(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
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/menu_entry.c normal/menu_text.c normal/charset.c \
normal/misc.c normal/crypto.c normal/term.c normal/context.c \ normal/misc.c normal/crypto.c normal/term.c normal/context.c \
unidata.c unidata.c
ifneq (, $(FONT_SOURCE))
normal/charset.c_SOURCES += widthspec.h
endif
normal_mod_CFLAGS = $(COMMON_CFLAGS) normal_mod_CFLAGS = $(COMMON_CFLAGS)
normal_mod_LDFLAGS = $(COMMON_LDFLAGS) 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 static inline grub_ssize_t
grub_term_getcharwidth (struct grub_term_output *term, grub_term_getcharwidth (struct grub_term_output *term,
const struct grub_unicode_glyph *c) const struct grub_unicode_glyph *c)
{ {
if (term->getcharwidth) if (term->getcharwidth)
return term->getcharwidth (c); 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 else
return 1; return 1;
} }

View file

@ -30,6 +30,10 @@
#include <grub/term.h> #include <grub/term.h>
#include <grub/normal.h> #include <grub/normal.h>
#ifdef HAVE_UNIFONT_WIDTHSPEC
#include "widthspec.h"
#endif
grub_ssize_t grub_ssize_t
grub_utf8_to_utf16 (grub_uint16_t *dest, grub_size_t destsize, grub_utf8_to_utf16 (grub_uint16_t *dest, grub_size_t destsize,
const grub_uint8_t *src, grub_size_t srcsize, 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; 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_size_t
grub_unicode_aglomerate_comb (const grub_uint32_t *in, grub_size_t inlen, grub_unicode_aglomerate_comb (const grub_uint32_t *in, grub_size_t inlen,
struct grub_unicode_glyph *out) 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) == GRUB_TERM_CODE_TYPE_UTF8_VISUAL)
{ {
int i; int i;
c2.estimated_width = 1; c2.estimated_width = grub_term_getcharwidth (term, c);
for (i = -1; i < (int) c->ncomb; i++) for (i = -1; i < (int) c->ncomb; i++)
{ {
grub_uint8_t u8[20], *ptr; grub_uint8_t u8[20], *ptr;
@ -1192,8 +1211,15 @@ grub_print_ucs4 (const grub_uint32_t * str,
grub_ssize_t visual_len; grub_ssize_t visual_len;
struct grub_unicode_glyph *visual; struct grub_unicode_glyph *visual;
struct grub_unicode_glyph *visual_ptr; 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_len = grub_bidi_logical_to_visual (str, last_position - str,
&visual, term->getcharwidth, &visual, getcharwidth,
max_width, startwidth); max_width, startwidth);
if (visual_len < 0) if (visual_len < 0)
{ {
@ -1231,7 +1257,7 @@ grub_print_ucs4 (const grub_uint32_t * str,
.combining = 0 .combining = 0
}; };
c.base = *ptr; c.base = *ptr;
line_width += last_width = term->getcharwidth (&c); line_width += last_width = grub_term_getcharwidth (term, &c);
} }
if (*ptr == ' ') if (*ptr == ' ')
@ -1279,7 +1305,15 @@ grub_print_ucs4 (const grub_uint32_t * str,
{ {
const grub_uint32_t *ptr2; const grub_uint32_t *ptr2;
for (ptr2 = line_start; ptr2 < last_position; 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); 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 static grub_uint16_t
grub_serial_getwh (void) grub_serial_getwh (void)
{ {
@ -449,7 +443,6 @@ static struct grub_term_output grub_serial_term_output =
{ {
.name = "serial", .name = "serial",
.putchar = grub_serial_putchar, .putchar = grub_serial_putchar,
.getcharwidth = grub_serial_getcharwidth,
.getwh = grub_serial_getwh, .getwh = grub_serial_getwh,
.getxy = grub_serial_getxy, .getxy = grub_serial_getxy,
.gotoxy = grub_serial_gotoxy, .gotoxy = grub_serial_gotoxy,

View file

@ -53,7 +53,8 @@ struct grub_glyph_info
enum file_formats enum file_formats
{ {
PF2, PF2,
ASCII_BITMAPS ASCII_BITMAPS,
WIDTH_SPEC
}; };
#define GRUB_FONT_FLAG_BOLD 1 #define GRUB_FONT_FLAG_BOLD 1
@ -95,6 +96,7 @@ static struct option options[] =
{"version", no_argument, 0, 'V'}, {"version", no_argument, 0, 'V'},
{"verbose", no_argument, 0, 'v'}, {"verbose", no_argument, 0, 'v'},
{"ascii-bitmaps", no_argument, 0, 0x102}, {"ascii-bitmaps", no_argument, 0, 0x102},
{"width-spec", no_argument, 0, 0x103},
{0, 0, 0, 0} {0, 0, 0, 0}
}; };
@ -111,6 +113,7 @@ Usage: %s [OPTIONS] FONT_FILES\n\
\nOptions:\n\ \nOptions:\n\
-o, --output=FILE_NAME set output file name\n\ -o, --output=FILE_NAME set output file name\n\
--ascii-bitmaps save only the ASCII bitmaps\n\ --ascii-bitmaps save only the ASCII bitmaps\n\
--width-spec create width summary file\n\
-i, --index=N set face index\n\ -i, --index=N set face index\n\
-r, --range=A-B[,C-D] set font range\n\ -r, --range=A-B[,C-D] set font range\n\
-n, --name=S set font family name\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); 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 void
write_font_pf2 (struct grub_font_info *font_info, char *output_file) 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; file_format = ASCII_BITMAPS;
break; break;
case 0x103:
file_format = WIDTH_SPEC;
break;
default: default:
usage (1); usage (1);
break; break;
@ -712,10 +745,20 @@ main (int argc, char *argv[])
FT_Done_FreeType (ft_lib); FT_Done_FreeType (ft_lib);
if (file_format == PF2) switch (file_format)
{
case PF2:
write_font_pf2 (&font_info, output_file); write_font_pf2 (&font_info, output_file);
else if (file_format == ASCII_BITMAPS) break;
case ASCII_BITMAPS:
write_font_ascii_bitmap (&font_info, output_file); 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) if (font_verbosity > 1)
print_glyphs (&font_info); print_glyphs (&font_info);