]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Fix doublewidth character handling
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Tue, 16 Mar 2010 20:29:15 +0000 (21:29 +0100)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Tue, 16 Mar 2010 20:29:15 +0000 (21:29 +0100)
Makefile.in
conf/common.rmk
include/grub/term.h
normal/charset.c
term/serial.c
util/grub-mkfont.c

index 07fe6219a2ef3638b16e8696b61ebef641ed1c1d..dd2fedbf4af22124b8e8f4d048feb7b38af0a5d9 100644 (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
 
index acbb990da71ce12e5264386f5a5682afc5f94713..98daa083982a7d7f47b25608fe4854081eee57c1 100644 (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)
 
index 573f20331f20b10b0b4d9fcff807a9a154aa7432..8a9218635cd37e8dd671d41021de7e767c33eed5 100644 (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;
 }
index af53b31342c8d1403eb1f3899e8c1859c1a1f076..143836bf2f36f3da2beb429d4cc6b85c209cef46 100644 (file)
 #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);
+       }
     }
   }
 }
index b1c5accd1b20f042523daec71496c41f6f1107b1..8b32396eeb75c05d649867089e8806d81ddf69a4 100644 (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,
index 9d94b687b1b1d87d24f08dcc3274cd1ca0a9d916..c7969011c5dc81b8e2627c5b32696d7cccc457f5 100644 (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);