diff --git a/Makefile.in b/Makefile.in index 07fe6219a..dd2fedbf4 100644 --- a/Makefile.in +++ b/Makefile.in @@ -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 diff --git a/conf/common.rmk b/conf/common.rmk index acbb990da..98daa0839 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -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) diff --git a/include/grub/term.h b/include/grub/term.h index 573f20331..8a9218635 100644 --- a/include/grub/term.h +++ b/include/grub/term.h @@ -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; } diff --git a/normal/charset.c b/normal/charset.c index af53b3134..143836bf2 100644 --- a/normal/charset.c +++ b/normal/charset.c @@ -30,6 +30,10 @@ #include #include +#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); + } } } } diff --git a/term/serial.c b/term/serial.c index b1c5accd1..8b32396ee 100644 --- a/term/serial.c +++ b/term/serial.c @@ -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, diff --git a/util/grub-mkfont.c b/util/grub-mkfont.c index 9d94b687b..c7969011c 100644 --- a/util/grub-mkfont.c +++ b/util/grub-mkfont.c @@ -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);