a5bd9f6
From c9b4dc3d736299b64bf79c87cef9b745d041c6ec Mon Sep 17 00:00:00 2001
a5bd9f6
From: Vladimir 'phcoder' Serbinenko <phcoder@gmail.com>
a5bd9f6
Date: Wed, 16 Jan 2013 13:41:16 +0100
a5bd9f6
Subject: [PATCH 109/364] 	Improve bidi handling in entry editor.
a5bd9f6
a5bd9f6
---
a5bd9f6
 ChangeLog                     |   4 +
a5bd9f6
 grub-core/gfxmenu/font.c      |   2 +-
a5bd9f6
 grub-core/normal/charset.c    |  98 ++++++++++-
a5bd9f6
 grub-core/normal/menu_entry.c | 394 ++++++++++++++++++------------------------
a5bd9f6
 grub-core/normal/term.c       | 186 +++++++++++++++++---
a5bd9f6
 include/grub/normal.h         |   8 +
a5bd9f6
 include/grub/term.h           |   6 +-
a5bd9f6
 include/grub/unicode.h        |  22 ++-
a5bd9f6
 8 files changed, 453 insertions(+), 267 deletions(-)
a5bd9f6
a5bd9f6
diff --git a/ChangeLog b/ChangeLog
a5bd9f6
index 76a9f68..96aca66 100644
a5bd9f6
--- a/ChangeLog
a5bd9f6
+++ b/ChangeLog
a5bd9f6
@@ -1,5 +1,9 @@
a5bd9f6
 2013-01-16  Vladimir Serbinenko  <phcoder@gmail.com>
a5bd9f6
 
a5bd9f6
+	Improve bidi handling in entry editor.
a5bd9f6
+
a5bd9f6
+2013-01-16  Vladimir Serbinenko  <phcoder@gmail.com>
a5bd9f6
+
a5bd9f6
 	* grub-core/script/lexer.c (grub_script_lexer_init): Rename getline
a5bd9f6
 	argument to prevent name collision.
a5bd9f6
 
a5bd9f6
diff --git a/grub-core/gfxmenu/font.c b/grub-core/gfxmenu/font.c
a5bd9f6
index 3c15e19..81a689d 100644
a5bd9f6
--- a/grub-core/gfxmenu/font.c
a5bd9f6
+++ b/grub-core/gfxmenu/font.c
a5bd9f6
@@ -52,7 +52,7 @@ grub_font_draw_string (const char *str, grub_font_t font,
a5bd9f6
     return grub_errno;
a5bd9f6
 
a5bd9f6
   visual_len = grub_bidi_logical_to_visual (logical, logical_len, &visual,
a5bd9f6
-					    0, 0, 0);
a5bd9f6
+					    0, 0, 0, 0, 0, 0);
a5bd9f6
   grub_free (logical);
a5bd9f6
   if (visual_len < 0)
a5bd9f6
     return grub_errno;
a5bd9f6
diff --git a/grub-core/normal/charset.c b/grub-core/normal/charset.c
a5bd9f6
index 25593ce..bd9fbf4 100644
a5bd9f6
--- a/grub-core/normal/charset.c
a5bd9f6
+++ b/grub-core/normal/charset.c
a5bd9f6
@@ -513,7 +513,10 @@ bidi_line_wrap (struct grub_unicode_glyph *visual_out,
a5bd9f6
 		struct grub_unicode_glyph *visual,
a5bd9f6
 		grub_size_t visual_len, unsigned *levels,
a5bd9f6
 		grub_ssize_t (*getcharwidth) (const struct grub_unicode_glyph *visual),
a5bd9f6
-		grub_size_t maxwidth, grub_size_t startwidth)
a5bd9f6
+		grub_size_t maxwidth, grub_size_t startwidth,
a5bd9f6
+		grub_uint32_t contchar,
a5bd9f6
+		struct grub_term_pos *pos, int primitive_wrap,
a5bd9f6
+		grub_size_t log_end)
a5bd9f6
 {
a5bd9f6
   struct grub_unicode_glyph *outptr = visual_out;
a5bd9f6
   unsigned line_start = 0;
a5bd9f6
@@ -521,17 +524,30 @@ bidi_line_wrap (struct grub_unicode_glyph *visual_out,
a5bd9f6
   unsigned k;
a5bd9f6
   grub_ssize_t last_space = -1;
a5bd9f6
   grub_ssize_t last_space_width = 0;
a5bd9f6
+  int lines = 0;
a5bd9f6
 
a5bd9f6
   auto void revert (unsigned start, unsigned end);
a5bd9f6
   void revert (unsigned start, unsigned end)
a5bd9f6
   {
a5bd9f6
     struct grub_unicode_glyph t;
a5bd9f6
     unsigned i, tl;
a5bd9f6
+    int a, b;
a5bd9f6
+    if (pos)
a5bd9f6
+      {
a5bd9f6
+	a = pos[visual[start].orig_pos].x;
a5bd9f6
+	b = pos[visual[end].orig_pos].x;
a5bd9f6
+      }
a5bd9f6
     for (i = 0; i < (end - start) / 2 + 1; i++)
a5bd9f6
       {
a5bd9f6
 	t = visual[start + i];
a5bd9f6
 	visual[start + i] = visual[end - i];
a5bd9f6
 	visual[end - i] = t;
a5bd9f6
+
a5bd9f6
+	if (pos)
a5bd9f6
+	  {
a5bd9f6
+	    pos[visual[start + i].orig_pos].x = a + b - pos[visual[start + i].orig_pos].x;
a5bd9f6
+	    pos[visual[end - i].orig_pos].x = a + b - pos[visual[end - i].orig_pos].x;
a5bd9f6
+	  }
a5bd9f6
 	tl = levels[start + i];
a5bd9f6
 	levels[start + i] = levels[end - i];
a5bd9f6
 	levels[end - i] = tl;
a5bd9f6
@@ -545,11 +561,27 @@ bidi_line_wrap (struct grub_unicode_glyph *visual_out,
a5bd9f6
     {
a5bd9f6
       grub_ssize_t last_width = 0;
a5bd9f6
 
a5bd9f6
+ 
a5bd9f6
+      if (pos && k != visual_len)
a5bd9f6
+	{
a5bd9f6
+	  pos[visual[k].orig_pos].x = line_width;
a5bd9f6
+	  pos[visual[k].orig_pos].y = lines;
a5bd9f6
+	  pos[visual[k].orig_pos].valid = 1;
a5bd9f6
+	}
a5bd9f6
+
a5bd9f6
+      if (k == visual_len && pos)
a5bd9f6
+	{
a5bd9f6
+	  pos[log_end].x = line_width;
a5bd9f6
+	  pos[log_end].y = lines;
a5bd9f6
+	  pos[log_end].valid = 1;
a5bd9f6
+	}
a5bd9f6
+
a5bd9f6
       if (getcharwidth && k != visual_len)
a5bd9f6
 	line_width += last_width = getcharwidth (&visual[k]);
a5bd9f6
 
a5bd9f6
       if (k != visual_len && (visual[k].base == ' '
a5bd9f6
-			      || visual[k].base == '\t'))
a5bd9f6
+			      || visual[k].base == '\t')
a5bd9f6
+	  && !primitive_wrap)
a5bd9f6
 	{
a5bd9f6
 	  last_space = k;
a5bd9f6
 	  last_space_width = line_width;
a5bd9f6
@@ -561,9 +593,12 @@ bidi_line_wrap (struct grub_unicode_glyph *visual_out,
a5bd9f6
 	  unsigned min_odd_level = 0xffffffff;
a5bd9f6
 	  unsigned max_level = 0;
a5bd9f6
 
a5bd9f6
+	  lines++;
a5bd9f6
+
a5bd9f6
 	  if (k != visual_len && last_space > (signed) line_start)
a5bd9f6
 	    k = last_space;
a5bd9f6
-	  else if (k != visual_len && line_start == 0 && startwidth != 0)
a5bd9f6
+	  else if (k != visual_len && line_start == 0 && startwidth != 0
a5bd9f6
+		   && !primitive_wrap)
a5bd9f6
 	    {
a5bd9f6
 	      k = 0;
a5bd9f6
 	      last_space_width = startwidth;
a5bd9f6
@@ -685,6 +720,12 @@ bidi_line_wrap (struct grub_unicode_glyph *visual_out,
a5bd9f6
 	  outptr += k - line_start;
a5bd9f6
 	  if (k != visual_len)
a5bd9f6
 	    {
a5bd9f6
+	      if (contchar)
a5bd9f6
+		{
a5bd9f6
+		  grub_memset (outptr, 0, sizeof (visual[0]));
a5bd9f6
+		  outptr->base = contchar;
a5bd9f6
+		  outptr++;
a5bd9f6
+		}
a5bd9f6
 	      grub_memset (outptr, 0, sizeof (visual[0]));
a5bd9f6
 	      outptr->base = '\n';
a5bd9f6
 	      outptr++;
a5bd9f6
@@ -695,6 +736,11 @@ bidi_line_wrap (struct grub_unicode_glyph *visual_out,
a5bd9f6
 
a5bd9f6
 	  line_start = k;
a5bd9f6
 	  line_width -= last_space_width;
a5bd9f6
+	  if (pos && k != visual_len)
a5bd9f6
+	    {
a5bd9f6
+	      pos[visual[k].orig_pos].x = 0;
a5bd9f6
+	      pos[visual[k].orig_pos].y = lines;
a5bd9f6
+	    }
a5bd9f6
 	}
a5bd9f6
     }
a5bd9f6
 
a5bd9f6
@@ -707,7 +753,11 @@ grub_bidi_line_logical_to_visual (const grub_uint32_t *logical,
a5bd9f6
 				  grub_size_t logical_len,
a5bd9f6
 				  struct grub_unicode_glyph *visual_out,
a5bd9f6
 				  grub_ssize_t (*getcharwidth) (const struct grub_unicode_glyph *visual),
a5bd9f6
-				  grub_size_t maxwidth, grub_size_t startwidth)
a5bd9f6
+				  grub_size_t maxwidth, grub_size_t startwidth,
a5bd9f6
+				  grub_uint32_t contchar,
a5bd9f6
+				  struct grub_term_pos *pos,
a5bd9f6
+				  int primitive_wrap,
a5bd9f6
+				  grub_size_t log_end)
a5bd9f6
 {
a5bd9f6
   enum grub_bidi_type type = GRUB_BIDI_TYPE_L;
a5bd9f6
   enum override_status {OVERRIDE_NEUTRAL = 0, OVERRIDE_R, OVERRIDE_L};
a5bd9f6
@@ -832,7 +882,7 @@ grub_bidi_line_logical_to_visual (const grub_uint32_t *logical,
a5bd9f6
 
a5bd9f6
 	p = grub_unicode_aglomerate_comb (lptr, logical + logical_len - lptr, 
a5bd9f6
 					  &visual[visual_len]);
a5bd9f6
-	
a5bd9f6
+	visual[visual_len].orig_pos = lptr - logical;
a5bd9f6
 	type = get_bidi_type (visual[visual_len].base);
a5bd9f6
 	switch (type)
a5bd9f6
 	  {
a5bd9f6
@@ -1066,7 +1116,8 @@ grub_bidi_line_logical_to_visual (const grub_uint32_t *logical,
a5bd9f6
   {
a5bd9f6
     grub_ssize_t ret;
a5bd9f6
     ret = bidi_line_wrap (visual_out, visual, visual_len, levels, 
a5bd9f6
-			  getcharwidth, maxwidth, startwidth);
a5bd9f6
+			  getcharwidth, maxwidth, startwidth, contchar,
a5bd9f6
+			  pos, primitive_wrap, log_end);
a5bd9f6
     grub_free (levels);
a5bd9f6
     grub_free (visual);
a5bd9f6
     return ret;
a5bd9f6
@@ -1078,11 +1129,12 @@ grub_bidi_logical_to_visual (const grub_uint32_t *logical,
a5bd9f6
 			     grub_size_t logical_len,
a5bd9f6
 			     struct grub_unicode_glyph **visual_out,
a5bd9f6
 			     grub_ssize_t (*getcharwidth) (const struct grub_unicode_glyph *visual),
a5bd9f6
-			     grub_size_t max_length, grub_size_t startwidth)
a5bd9f6
+			     grub_size_t max_length, grub_size_t startwidth,
a5bd9f6
+			     grub_uint32_t contchar, struct grub_term_pos *pos, int primitive_wrap)
a5bd9f6
 {
a5bd9f6
   const grub_uint32_t *line_start = logical, *ptr;
a5bd9f6
   struct grub_unicode_glyph *visual_ptr;
a5bd9f6
-  *visual_out = visual_ptr = grub_malloc (2 * sizeof (visual_ptr[0])
a5bd9f6
+  *visual_out = visual_ptr = grub_malloc (3 * sizeof (visual_ptr[0])
a5bd9f6
 					  * logical_len);
a5bd9f6
   if (!visual_ptr)
a5bd9f6
     return -1;
a5bd9f6
@@ -1096,7 +1148,11 @@ grub_bidi_logical_to_visual (const grub_uint32_t *logical,
a5bd9f6
 						  visual_ptr,
a5bd9f6
 						  getcharwidth,
a5bd9f6
 						  max_length,
a5bd9f6
-						  startwidth);
a5bd9f6
+						  startwidth,
a5bd9f6
+						  contchar,
a5bd9f6
+						  pos,
a5bd9f6
+						  primitive_wrap,
a5bd9f6
+						  logical_len);
a5bd9f6
 	  startwidth = 0;
a5bd9f6
 
a5bd9f6
 	  if (ret < 0)
a5bd9f6
@@ -1188,3 +1244,27 @@ grub_unicode_get_comb_start (const grub_uint32_t *str,
a5bd9f6
   return str;
a5bd9f6
 }
a5bd9f6
 
a5bd9f6
+const grub_uint32_t *
a5bd9f6
+grub_unicode_get_comb_end (const grub_uint32_t *end, 
a5bd9f6
+			   const grub_uint32_t *cur)
a5bd9f6
+{
a5bd9f6
+  const grub_uint32_t *ptr;
a5bd9f6
+  for (ptr = cur; ptr < end; ptr++)
a5bd9f6
+    {
a5bd9f6
+      if (*ptr >= GRUB_UNICODE_VARIATION_SELECTOR_1
a5bd9f6
+	  && *ptr <= GRUB_UNICODE_VARIATION_SELECTOR_16)
a5bd9f6
+	continue;
a5bd9f6
+
a5bd9f6
+      if (*ptr >= GRUB_UNICODE_VARIATION_SELECTOR_17
a5bd9f6
+	  && *ptr <= GRUB_UNICODE_VARIATION_SELECTOR_256)
a5bd9f6
+	continue;
a5bd9f6
+	
a5bd9f6
+      enum grub_comb_type comb_type;
a5bd9f6
+      comb_type = grub_unicode_get_comb_type (*ptr);
a5bd9f6
+      if (comb_type)
a5bd9f6
+	continue;
a5bd9f6
+      return ptr;
a5bd9f6
+    }
a5bd9f6
+  return end;
a5bd9f6
+}
a5bd9f6
+
a5bd9f6
diff --git a/grub-core/normal/menu_entry.c b/grub-core/normal/menu_entry.c
a5bd9f6
index 33b644b..7cd67f3 100644
a5bd9f6
--- a/grub-core/normal/menu_entry.c
a5bd9f6
+++ b/grub-core/normal/menu_entry.c
a5bd9f6
@@ -43,15 +43,12 @@ struct line
a5bd9f6
   int len;
a5bd9f6
   /* The maximum length of the line.  */
a5bd9f6
   int max_len;
a5bd9f6
+  struct grub_term_pos **pos;
a5bd9f6
 };
a5bd9f6
 
a5bd9f6
 struct per_term_screen
a5bd9f6
 {
a5bd9f6
   struct grub_term_output *term;
a5bd9f6
-  /* The X coordinate.  */
a5bd9f6
-  int x;
a5bd9f6
-  /* The Y coordinate.  */
a5bd9f6
-  int y;
a5bd9f6
   int y_line_start;
a5bd9f6
   /* Number of entries.  */
a5bd9f6
   int num_entries;
a5bd9f6
@@ -90,13 +87,18 @@ static int completion_type;
a5bd9f6
 
a5bd9f6
 /* Initialize a line.  */
a5bd9f6
 static int
a5bd9f6
-init_line (struct line *linep)
a5bd9f6
+init_line (struct screen *screen, struct line *linep)
a5bd9f6
 {
a5bd9f6
   linep->len = 0;
a5bd9f6
   linep->max_len = 80;
a5bd9f6
   linep->buf = grub_malloc ((linep->max_len + 1) * sizeof (linep->buf[0]));
a5bd9f6
-  if (! linep->buf)
a5bd9f6
-    return 0;
a5bd9f6
+  linep->pos = grub_zalloc (screen->nterms * sizeof (linep->pos[0]));
a5bd9f6
+  if (! linep->buf || !linep->pos)
a5bd9f6
+    {
a5bd9f6
+      grub_free (linep->buf);
a5bd9f6
+      grub_free (linep->pos);
a5bd9f6
+      return 0;
a5bd9f6
+    }
a5bd9f6
 
a5bd9f6
   return 1;
a5bd9f6
 }
a5bd9f6
@@ -126,93 +128,16 @@ get_logical_num_lines (struct line *linep, struct per_term_screen *term_screen)
a5bd9f6
 }
a5bd9f6
 
a5bd9f6
 static void
a5bd9f6
-advance (struct screen *screen)
a5bd9f6
-{
a5bd9f6
-  unsigned i;
a5bd9f6
-  struct grub_unicode_glyph glyph;
a5bd9f6
-
a5bd9f6
-  screen->column += grub_unicode_aglomerate_comb (screen->lines[screen->line].buf + screen->column,
a5bd9f6
-						  screen->lines[screen->line].len - screen->column,
a5bd9f6
-						  &glyph);
a5bd9f6
-
a5bd9f6
-  for (i = 0; i < screen->nterms; i++)
a5bd9f6
-    {
a5bd9f6
-      grub_ssize_t width;
a5bd9f6
-      width = grub_term_getcharwidth (screen->terms[i].term, &glyph);
a5bd9f6
-      screen->terms[i].x += width;
a5bd9f6
-      if (screen->terms[i].x
a5bd9f6
-	  == grub_term_entry_width (screen->terms[i].term))
a5bd9f6
-	{
a5bd9f6
-	  screen->terms[i].x = 0;
a5bd9f6
-	  screen->terms[i].y++;
a5bd9f6
-	}
a5bd9f6
-      if (screen->terms[i].x
a5bd9f6
-	  > grub_term_entry_width (screen->terms[i].term))
a5bd9f6
-	{
a5bd9f6
-	  screen->terms[i].x = width;
a5bd9f6
-	  screen->terms[i].y++;
a5bd9f6
-	}
a5bd9f6
-    }
a5bd9f6
-  grub_free (glyph.combining);
a5bd9f6
-}
a5bd9f6
-
a5bd9f6
-static void
a5bd9f6
 advance_to (struct screen *screen, int c)
a5bd9f6
 {
a5bd9f6
   if (c > screen->lines[screen->line].len)
a5bd9f6
     c = screen->lines[screen->line].len;
a5bd9f6
 
a5bd9f6
-  while (screen->column < c)
a5bd9f6
-    advance (screen);
a5bd9f6
-}
a5bd9f6
-
a5bd9f6
-/* Print a line.  */
a5bd9f6
-static int
a5bd9f6
-print_line (struct line *linep, int offset, int y,
a5bd9f6
-	    struct per_term_screen *term_screen, int dry_run)
a5bd9f6
-{
a5bd9f6
-  int x;
a5bd9f6
-  int i;
a5bd9f6
-
a5bd9f6
-  grub_term_gotoxy (term_screen->term, 
a5bd9f6
- 		    GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + 1,
a5bd9f6
- 		    y + GRUB_TERM_FIRST_ENTRY_Y);
a5bd9f6
- 
a5bd9f6
-  x = 0;
a5bd9f6
-  for (i = 0; i + offset < (int) linep->len;)
a5bd9f6
-     {
a5bd9f6
-      grub_ssize_t width;
a5bd9f6
-      grub_size_t delta = 0;
a5bd9f6
-      struct grub_unicode_glyph glyph;
a5bd9f6
-
a5bd9f6
-      delta = grub_unicode_aglomerate_comb (linep->buf + offset + i,
a5bd9f6
-					    linep->len - offset - i,
a5bd9f6
-					    &glyph);
a5bd9f6
-      width = grub_term_getcharwidth (term_screen->term, &glyph);
a5bd9f6
-      grub_free (glyph.combining);
a5bd9f6
-
a5bd9f6
-      if (x + width > grub_term_entry_width (term_screen->term) && x != 0)
a5bd9f6
-	break;
a5bd9f6
-      x += width;
a5bd9f6
-      i += delta;
a5bd9f6
-     }
a5bd9f6
-
a5bd9f6
-  if (dry_run)
a5bd9f6
-    return i;
a5bd9f6
-
a5bd9f6
-  grub_print_ucs4 (linep->buf + offset,
a5bd9f6
-		   linep->buf + offset + i, 0, 0, term_screen->term);
a5bd9f6
-
a5bd9f6
-  if (i + offset != linep->len)
a5bd9f6
-    grub_putcode ('\\', term_screen->term);
a5bd9f6
-   else
a5bd9f6
-     {
a5bd9f6
-       for (;
a5bd9f6
-	    x <= (int) grub_term_entry_width (term_screen->term);
a5bd9f6
-	    x++)
a5bd9f6
-	 grub_putcode (' ', term_screen->term);
a5bd9f6
-     }
a5bd9f6
-  return i;
a5bd9f6
+  screen->column = grub_unicode_get_comb_end (screen->lines[screen->line].buf
a5bd9f6
+					      + screen->lines[screen->line].len,
a5bd9f6
+					      screen->lines[screen->line].buf
a5bd9f6
+					      + c)
a5bd9f6
+    - screen->lines[screen->line].buf;
a5bd9f6
 }
a5bd9f6
 
a5bd9f6
 /* Print an empty line.  */
a5bd9f6
@@ -225,7 +150,7 @@ print_empty_line (int y, struct per_term_screen *term_screen)
a5bd9f6
 		    GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + 1,
a5bd9f6
 		    y + GRUB_TERM_FIRST_ENTRY_Y);
a5bd9f6
 
a5bd9f6
-  for (i = 0; i < grub_term_entry_width (term_screen->term) + 1; i++)
a5bd9f6
+  for (i = 0; i < grub_term_entry_width (term_screen->term); i++)
a5bd9f6
     grub_putcode (' ', term_screen->term);
a5bd9f6
 }
a5bd9f6
 
a5bd9f6
@@ -261,7 +186,7 @@ print_down (int flag, struct per_term_screen *term_screen)
a5bd9f6
 /* Draw the lines of the screen SCREEN.  */
a5bd9f6
 static void
a5bd9f6
 update_screen (struct screen *screen, struct per_term_screen *term_screen,
a5bd9f6
-	       int region_start, int region_column,
a5bd9f6
+	       int region_start, int region_column __attribute__ ((unused)),
a5bd9f6
 	       int up, int down, enum update_mode mode)
a5bd9f6
 {
a5bd9f6
   int up_flag = 0;
a5bd9f6
@@ -270,19 +195,26 @@ update_screen (struct screen *screen, struct per_term_screen *term_screen,
a5bd9f6
   int i;
a5bd9f6
   struct line *linep;
a5bd9f6
 
a5bd9f6
+  y = term_screen->y_line_start;
a5bd9f6
+  linep = screen->lines;
a5bd9f6
+
a5bd9f6
+  for (i = 0; i < screen->line; i++, linep++)
a5bd9f6
+    y += get_logical_num_lines (linep, term_screen);
a5bd9f6
+  linep = screen->lines + screen->line;
a5bd9f6
+  y += grub_getstringwidth (linep->buf, linep->buf + screen->column,
a5bd9f6
+			    term_screen->term) / grub_term_entry_width (term_screen->term);
a5bd9f6
+
a5bd9f6
   /* Check if scrolling is necessary.  */
a5bd9f6
-  if (term_screen->y < 0 || term_screen->y >= term_screen->num_entries)
a5bd9f6
+  if (y < 0 || y >= term_screen->num_entries)
a5bd9f6
     {
a5bd9f6
       int delta;
a5bd9f6
-      if (term_screen->y < 0)
a5bd9f6
-	delta = -term_screen->y;
a5bd9f6
+      if (y < 0)
a5bd9f6
+	delta = -y;
a5bd9f6
       else
a5bd9f6
-	delta = term_screen->num_entries - 1 - term_screen->y;
a5bd9f6
-      term_screen->y += delta;
a5bd9f6
+	delta = term_screen->num_entries - 1 - y;
a5bd9f6
       term_screen->y_line_start += delta;
a5bd9f6
 
a5bd9f6
       region_start = 0;
a5bd9f6
-      region_column = 0;
a5bd9f6
       up = 1;
a5bd9f6
       down = 1;
a5bd9f6
       mode = ALL_LINES;
a5bd9f6
@@ -293,58 +225,81 @@ update_screen (struct screen *screen, struct per_term_screen *term_screen,
a5bd9f6
       /* Draw lines. This code is tricky, because this must calculate logical
a5bd9f6
 	 positions.  */
a5bd9f6
       y = term_screen->y_line_start;
a5bd9f6
-      i = screen->line;
a5bd9f6
-      linep = screen->lines + i;
a5bd9f6
-      while (y > 0)
a5bd9f6
-	{
a5bd9f6
-	   i--;
a5bd9f6
-	   linep--;
a5bd9f6
-	   y -= get_logical_num_lines (linep, term_screen);
a5bd9f6
-	}
a5bd9f6
+      i = 0;
a5bd9f6
+      linep = screen->lines;
a5bd9f6
+      while (1)
a5bd9f6
+ 	{
a5bd9f6
+	  int add;
a5bd9f6
+	  add = get_logical_num_lines (linep, term_screen);
a5bd9f6
+	  if (y + add > 0)
a5bd9f6
+	    break;
a5bd9f6
+	  i++;
a5bd9f6
+	  linep++;
a5bd9f6
+	  y += add;
a5bd9f6
+ 	}
a5bd9f6
 
a5bd9f6
       if (y < 0 || i > 0)
a5bd9f6
 	up_flag = 1;
a5bd9f6
 
a5bd9f6
       do
a5bd9f6
 	{
a5bd9f6
-	  int column;
a5bd9f6
 	  int off = 0;
a5bd9f6
-	  int full_len;
a5bd9f6
+	  struct grub_term_pos **pos;
a5bd9f6
 
a5bd9f6
 	  if (linep >= screen->lines + screen->num_lines)
a5bd9f6
 	    break;
a5bd9f6
 
a5bd9f6
-	  full_len = grub_getstringwidth (linep->buf, linep->buf + linep->len,
a5bd9f6
-					  term_screen->term);
a5bd9f6
+	  pos = linep->pos + (term_screen - screen->terms);
a5bd9f6
 
a5bd9f6
-	  for (column = 0;
a5bd9f6
-	       column <= full_len
a5bd9f6
-		 && y < term_screen->num_entries;
a5bd9f6
-	       column += grub_term_entry_width (term_screen->term), y++)
a5bd9f6
+	  if (!*pos)
a5bd9f6
+	    *pos = grub_zalloc ((linep->len + 1) * sizeof (**pos));
a5bd9f6
+
a5bd9f6
+	  if (i == region_start || linep == screen->lines + screen->line)
a5bd9f6
+	    {
a5bd9f6
+	      int sp;
a5bd9f6
+	      grub_term_gotoxy (term_screen->term, GRUB_TERM_LEFT_BORDER_X
a5bd9f6
+				+ GRUB_TERM_MARGIN + 1, (y < 0 ? 0 : y)
a5bd9f6
+				+ GRUB_TERM_FIRST_ENTRY_Y);
a5bd9f6
+	      grub_print_ucs4_menu (linep->buf,
a5bd9f6
+				    linep->buf + linep->len,
a5bd9f6
+				    GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN
a5bd9f6
+				    + 1,
a5bd9f6
+				    GRUB_TERM_MARGIN
a5bd9f6
+				    + GRUB_TERM_SCROLL_WIDTH + 2,
a5bd9f6
+				    term_screen->term,
a5bd9f6
+				    (y < 0) ? -y : 0,
a5bd9f6
+				    term_screen->num_entries
a5bd9f6
+				    - ((y > 0) ? y : 0), '\\',
a5bd9f6
+				    *pos);
a5bd9f6
+	      sp = grub_term_entry_width (term_screen->term)
a5bd9f6
+		 - (*pos)[linep->len].x;
a5bd9f6
+	      if (sp > 0)
a5bd9f6
+		grub_print_spaces (term_screen->term, sp);
a5bd9f6
+ 	    }
a5bd9f6
+	  else if (i > region_start && mode == ALL_LINES)
a5bd9f6
 	    {
a5bd9f6
-	      if (y < 0)
a5bd9f6
-		{
a5bd9f6
-		  off += print_line (linep, off, y, term_screen, 1);
a5bd9f6
-		  continue;
a5bd9f6
-		}
a5bd9f6
-
a5bd9f6
-	      if (i == region_start)
a5bd9f6
-		{
a5bd9f6
-		  if (region_column >= column
a5bd9f6
-		      && region_column
a5bd9f6
-		      < (column
a5bd9f6
-			 + grub_term_entry_width (term_screen->term)))
a5bd9f6
-		    off += print_line (linep, off, y, term_screen, 0);
a5bd9f6
-		  else if (region_column < column)
a5bd9f6
-		    off += print_line (linep, off, y, term_screen, 0);
a5bd9f6
-		  else
a5bd9f6
-		    off += print_line (linep, off, y, term_screen, 1);
a5bd9f6
-		}
a5bd9f6
-	      else if (i > region_start && mode == ALL_LINES)
a5bd9f6
-		off += print_line (linep, off, y, term_screen, 0);
a5bd9f6
+	      int sp;
a5bd9f6
+	      grub_term_gotoxy (term_screen->term, GRUB_TERM_LEFT_BORDER_X
a5bd9f6
+				+ GRUB_TERM_MARGIN + 1, (y < 0 ? 0 : y)
a5bd9f6
+				+ GRUB_TERM_FIRST_ENTRY_Y);
a5bd9f6
+	      grub_print_ucs4_menu (linep->buf,
a5bd9f6
+				    linep->buf + linep->len,
a5bd9f6
+				    GRUB_TERM_LEFT_BORDER_X
a5bd9f6
+			    + GRUB_TERM_MARGIN + 1,
a5bd9f6
+				    GRUB_TERM_MARGIN
a5bd9f6
+				    + GRUB_TERM_SCROLL_WIDTH + 2,
a5bd9f6
+				    term_screen->term,
a5bd9f6
+				    (y < 0) ? -y : 0,
a5bd9f6
+				    term_screen->num_entries
a5bd9f6
+				    - ((y > 0) ? y : 0), '\\',
a5bd9f6
+				    *pos);
a5bd9f6
+	      sp = grub_term_entry_width (term_screen->term)
a5bd9f6
+		- (*pos)[linep->len].x;
a5bd9f6
+	      if (sp > 0)
a5bd9f6
+		grub_print_spaces (term_screen->term, sp);
a5bd9f6
 	    }
a5bd9f6
-
a5bd9f6
-	  if (y == term_screen->num_entries)
a5bd9f6
+	  y += get_logical_num_lines (linep, term_screen);
a5bd9f6
+	  if (y >= term_screen->num_entries)
a5bd9f6
 	    {
a5bd9f6
 	      if (off <= linep->len || i + 1 < screen->num_lines)
a5bd9f6
 		down_flag = 1;
a5bd9f6
@@ -367,10 +322,30 @@ update_screen (struct screen *screen, struct per_term_screen *term_screen,
a5bd9f6
     }
a5bd9f6
 
a5bd9f6
   /* Place the cursor.  */
a5bd9f6
-  grub_term_gotoxy (term_screen->term, 
a5bd9f6
-		    GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + 1
a5bd9f6
-		    + term_screen->x,
a5bd9f6
-		    GRUB_TERM_FIRST_ENTRY_Y + term_screen->y);
a5bd9f6
+  if (screen->lines[screen->line].pos[term_screen - screen->terms])
a5bd9f6
+    {
a5bd9f6
+      const struct grub_term_pos *cpos;
a5bd9f6
+      for (cpos = &(screen->lines[screen->line].pos[term_screen - screen->terms])[screen->column];
a5bd9f6
+	   cpos >= &(screen->lines[screen->line].pos[term_screen - screen->terms])[0];
a5bd9f6
+	   cpos--)
a5bd9f6
+	if (cpos->valid)
a5bd9f6
+	  break;
a5bd9f6
+      y = term_screen->y_line_start;
a5bd9f6
+      for (i = 0; i < screen->line; i++)
a5bd9f6
+	y += get_logical_num_lines (screen->lines + i, term_screen);
a5bd9f6
+      if (cpos >= &(screen->lines[screen->line].pos[term_screen - screen->terms])[0])
a5bd9f6
+	grub_term_gotoxy (term_screen->term, 
a5bd9f6
+			  cpos->x + GRUB_TERM_LEFT_BORDER_X
a5bd9f6
+			  + GRUB_TERM_MARGIN + 1,
a5bd9f6
+			  cpos->y + y
a5bd9f6
+			  + GRUB_TERM_FIRST_ENTRY_Y);
a5bd9f6
+      else
a5bd9f6
+	grub_term_gotoxy (term_screen->term, 
a5bd9f6
+			  GRUB_TERM_LEFT_BORDER_X
a5bd9f6
+			  + GRUB_TERM_MARGIN + 1,
a5bd9f6
+			  y + GRUB_TERM_FIRST_ENTRY_Y);
a5bd9f6
+
a5bd9f6
+    }
a5bd9f6
 
a5bd9f6
   grub_term_refresh (term_screen->term);
a5bd9f6
 }
a5bd9f6
@@ -424,7 +399,7 @@ insert_string (struct screen *screen, const char *s, int update)
a5bd9f6
 			((screen->num_lines - screen->line - 2)
a5bd9f6
 			 * sizeof (struct line)));
a5bd9f6
 
a5bd9f6
-	  if (! init_line (screen->lines + screen->line + 1))
a5bd9f6
+	  if (! init_line (screen, screen->lines + screen->line + 1))
a5bd9f6
 	    return 0;
a5bd9f6
 
a5bd9f6
 	  /* Fold the line.  */
a5bd9f6
@@ -439,6 +414,11 @@ insert_string (struct screen *screen, const char *s, int update)
a5bd9f6
 			current_linep->buf + screen->column,
a5bd9f6
 			size * sizeof (next_linep->buf[0]));
a5bd9f6
 	  current_linep->len = screen->column;
a5bd9f6
+	  for (i = 0; i < screen->nterms; i++)
a5bd9f6
+	    {
a5bd9f6
+	      grub_free (current_linep->pos[i]);
a5bd9f6
+	      current_linep->pos[i] = 0;
a5bd9f6
+	    }
a5bd9f6
 	  next_linep->len = size;
a5bd9f6
 
a5bd9f6
 	  /* Update a dirty region.  */
a5bd9f6
@@ -457,12 +437,6 @@ insert_string (struct screen *screen, const char *s, int update)
a5bd9f6
 	  /* Move the cursor.  */
a5bd9f6
 	  screen->column = screen->real_column = 0;
a5bd9f6
 	  screen->line++;
a5bd9f6
-	  for (i = 0; i < screen->nterms; i++)
a5bd9f6
-	    {
a5bd9f6
-	      screen->terms[i].x = 0;
a5bd9f6
-	      screen->terms[i].y++;
a5bd9f6
-	      screen->terms[i].y_line_start = screen->terms[i].y;
a5bd9f6
-	    }
a5bd9f6
 	  s++;
a5bd9f6
 	}
a5bd9f6
       else
a5bd9f6
@@ -502,6 +476,12 @@ insert_string (struct screen *screen, const char *s, int update)
a5bd9f6
 	  grub_free (unicode_msg);
a5bd9f6
 
a5bd9f6
 	  for (i = 0; i < screen->nterms; i++)
a5bd9f6
+	    {
a5bd9f6
+	      grub_free (current_linep->pos[i]);
a5bd9f6
+	      current_linep->pos[i] = 0;
a5bd9f6
+	    }
a5bd9f6
+
a5bd9f6
+	  for (i = 0; i < screen->nterms; i++)
a5bd9f6
 	    orig_num[i] = get_logical_num_lines (current_linep,
a5bd9f6
 						 &screen->terms[i]);
a5bd9f6
 	  current_linep->len += size;
a5bd9f6
@@ -582,7 +562,7 @@ make_screen (grub_menu_entry_t entry)
a5bd9f6
     goto fail;
a5bd9f6
 
a5bd9f6
   /* Initialize the first line which must be always present.  */
a5bd9f6
-  if (! init_line (screen->lines))
a5bd9f6
+  if (! init_line (screen, screen->lines))
a5bd9f6
     goto fail;
a5bd9f6
 
a5bd9f6
   insert_string (screen, (char *) entry->sourcecode, 0);
a5bd9f6
@@ -593,9 +573,7 @@ make_screen (grub_menu_entry_t entry)
a5bd9f6
   screen->line = 0;
a5bd9f6
   for (i = 0; i < screen->nterms; i++)
a5bd9f6
     {
a5bd9f6
-      screen->terms[i].x = 0;
a5bd9f6
-      screen->terms[i].y = 0;
a5bd9f6
-      screen->terms[i].y_line_start = screen->terms[i].y;
a5bd9f6
+      screen->terms[i].y_line_start = 0;
a5bd9f6
     }
a5bd9f6
 
a5bd9f6
   return screen;
a5bd9f6
@@ -609,21 +587,20 @@ static int
a5bd9f6
 forward_char (struct screen *screen, int update)
a5bd9f6
 {
a5bd9f6
   struct line *linep;
a5bd9f6
-  unsigned i;
a5bd9f6
 
a5bd9f6
   linep = screen->lines + screen->line;
a5bd9f6
   if (screen->column < linep->len)
a5bd9f6
-    advance (screen);
a5bd9f6
+    {
a5bd9f6
+      screen->column = grub_unicode_get_comb_end (screen->lines[screen->line].buf
a5bd9f6
+						  + screen->lines[screen->line].len,
a5bd9f6
+						  screen->lines[screen->line].buf
a5bd9f6
+						  + screen->column + 1)
a5bd9f6
+	- screen->lines[screen->line].buf;
a5bd9f6
+    }
a5bd9f6
   else if (screen->num_lines > screen->line + 1)
a5bd9f6
     {
a5bd9f6
       screen->column = 0;
a5bd9f6
       screen->line++;
a5bd9f6
-      for (i = 0; i < screen->nterms; i++)
a5bd9f6
-	{
a5bd9f6
-	  screen->terms[i].x = 0;
a5bd9f6
-	  screen->terms[i].y++;
a5bd9f6
-	  screen->terms[i].y_line_start = screen->terms[i].y;
a5bd9f6
-	}
a5bd9f6
     }
a5bd9f6
 
a5bd9f6
   screen->real_column = screen->column;
a5bd9f6
@@ -636,8 +613,6 @@ forward_char (struct screen *screen, int update)
a5bd9f6
 static int
a5bd9f6
 backward_char (struct screen *screen, int update)
a5bd9f6
 {
a5bd9f6
-  unsigned i;
a5bd9f6
-
a5bd9f6
   if (screen->column > 0)
a5bd9f6
     {
a5bd9f6
       struct grub_unicode_glyph glyph;
a5bd9f6
@@ -653,36 +628,16 @@ backward_char (struct screen *screen, int update)
a5bd9f6
       grub_unicode_aglomerate_comb (screen->lines[screen->line].buf + screen->column,
a5bd9f6
 				    screen->lines[screen->line].len - screen->column,
a5bd9f6
 				    &glyph);
a5bd9f6
+      screen->column = grub_unicode_get_comb_start (linep->buf, 
a5bd9f6
+						    linep->buf + screen->column)
a5bd9f6
+	- linep->buf;
a5bd9f6
 
a5bd9f6
-      for (i = 0; i < screen->nterms; i++)
a5bd9f6
-	{
a5bd9f6
-	  grub_ssize_t width;
a5bd9f6
-	  width = grub_term_getcharwidth (screen->terms[i].term, &glyph);
a5bd9f6
-	  screen->terms[i].x -= width;
a5bd9f6
-	  if (screen->terms[i].x < 0)
a5bd9f6
-	    {
a5bd9f6
-	      screen->terms[i].x
a5bd9f6
-		= grub_term_entry_width (screen->terms[i].term) - 1;
a5bd9f6
-	      screen->terms[i].y--;
a5bd9f6
-	    }
a5bd9f6
-	}
a5bd9f6
       grub_free (glyph.combining);
a5bd9f6
     }
a5bd9f6
   else if (screen->line > 0)
a5bd9f6
     {
a5bd9f6
-      struct line *linep;
a5bd9f6
-
a5bd9f6
-      screen->column = 0;
a5bd9f6
       screen->line--;
a5bd9f6
-      linep = screen->lines + screen->line;
a5bd9f6
-
a5bd9f6
-      for (i = 0; i < screen->nterms; i++)
a5bd9f6
-	{
a5bd9f6
-	  screen->terms[i].y_line_start -= get_logical_num_lines (linep, &screen->terms[i]);
a5bd9f6
-	  screen->terms[i].y = screen->terms[i].y_line_start;
a5bd9f6
-	  screen->terms[i].x = 0;
a5bd9f6
-	}
a5bd9f6
-      advance_to (screen, screen->lines[screen->line].len);
a5bd9f6
+      screen->column = screen->lines[screen->line].len;
a5bd9f6
     }
a5bd9f6
 
a5bd9f6
   screen->real_column = screen->column;
a5bd9f6
@@ -696,8 +651,6 @@ backward_char (struct screen *screen, int update)
a5bd9f6
 static int
a5bd9f6
 previous_line (struct screen *screen, int update)
a5bd9f6
 {
a5bd9f6
-  unsigned i;
a5bd9f6
-
a5bd9f6
   if (screen->line > 0)
a5bd9f6
     {
a5bd9f6
       struct line *linep;
a5bd9f6
@@ -712,22 +665,10 @@ previous_line (struct screen *screen, int update)
a5bd9f6
 	col = screen->real_column;
a5bd9f6
 
a5bd9f6
       screen->column = 0;
a5bd9f6
-
a5bd9f6
-      for (i = 0; i < screen->nterms; i++)
a5bd9f6
-	{
a5bd9f6
-	  screen->terms[i].y_line_start -= get_logical_num_lines (linep, &screen->terms[i]);
a5bd9f6
-	  screen->terms[i].y = screen->terms[i].y_line_start;
a5bd9f6
-	  screen->terms[i].x = 0;
a5bd9f6
-	}
a5bd9f6
       advance_to (screen, col);
a5bd9f6
     }
a5bd9f6
   else
a5bd9f6
     {
a5bd9f6
-      for (i = 0; i < screen->nterms; i++)
a5bd9f6
-	{
a5bd9f6
-	  screen->terms[i].y = screen->terms[i].y_line_start;
a5bd9f6
-	  screen->terms[i].x = 0;
a5bd9f6
-	}
a5bd9f6
       screen->column = 0;
a5bd9f6
     }
a5bd9f6
 
a5bd9f6
@@ -740,8 +681,6 @@ previous_line (struct screen *screen, int update)
a5bd9f6
 static int
a5bd9f6
 next_line (struct screen *screen, int update)
a5bd9f6
 {
a5bd9f6
-  unsigned i;
a5bd9f6
-
a5bd9f6
   if (screen->line < screen->num_lines - 1)
a5bd9f6
     {
a5bd9f6
       struct line *linep;
a5bd9f6
@@ -758,12 +697,6 @@ next_line (struct screen *screen, int update)
a5bd9f6
 	c = screen->real_column;
a5bd9f6
       screen->column = 0;
a5bd9f6
 
a5bd9f6
-      for (i = 0; i < screen->nterms; i++)
a5bd9f6
-	{
a5bd9f6
-	  screen->terms[i].y_line_start += get_logical_num_lines (linep, &screen->terms[i]);
a5bd9f6
-	  screen->terms[i].x = 0;
a5bd9f6
-	  screen->terms[i].y = screen->terms[i].y_line_start;
a5bd9f6
-	}
a5bd9f6
       advance_to (screen, c);
a5bd9f6
     }
a5bd9f6
   else
a5bd9f6
@@ -778,14 +711,7 @@ next_line (struct screen *screen, int update)
a5bd9f6
 static int
a5bd9f6
 beginning_of_line (struct screen *screen, int update)
a5bd9f6
 {
a5bd9f6
-  unsigned i;
a5bd9f6
-
a5bd9f6
   screen->column = screen->real_column = 0;
a5bd9f6
-  for (i = 0; i < screen->nterms; i++)
a5bd9f6
-    {
a5bd9f6
-      screen->terms[i].x = 0;
a5bd9f6
-      screen->terms[i].y = screen->terms[i].y_line_start;
a5bd9f6
-    }
a5bd9f6
 
a5bd9f6
   if (update)
a5bd9f6
     update_screen_all (screen, screen->num_lines, 0, 0, 0, NO_LINE);
a5bd9f6
@@ -826,6 +752,11 @@ delete_char (struct screen *screen, int update)
a5bd9f6
 		    * sizeof (linep->buf[0]));
a5bd9f6
       linep->len--;
a5bd9f6
 
a5bd9f6
+      for (i = 0; i < screen->nterms; i++)
a5bd9f6
+	{
a5bd9f6
+	  grub_free (linep->pos[i]);
a5bd9f6
+	  linep->pos[i] = 0;
a5bd9f6
+	}
a5bd9f6
       start = screen->line;
a5bd9f6
       column = screen->column;
a5bd9f6
 
a5bd9f6
@@ -848,6 +779,7 @@ delete_char (struct screen *screen, int update)
a5bd9f6
   else if (screen->num_lines > screen->line + 1)
a5bd9f6
     {
a5bd9f6
       struct line *next_linep;
a5bd9f6
+      unsigned i;
a5bd9f6
 
a5bd9f6
       next_linep = linep + 1;
a5bd9f6
       if (! ensure_space (linep, next_linep->len))
a5bd9f6
@@ -856,6 +788,11 @@ delete_char (struct screen *screen, int update)
a5bd9f6
       grub_memmove (linep->buf + linep->len, next_linep->buf,
a5bd9f6
 		    next_linep->len * sizeof (linep->buf[0]));
a5bd9f6
       linep->len += next_linep->len;
a5bd9f6
+      for (i = 0; i < screen->nterms; i++)
a5bd9f6
+	{
a5bd9f6
+	  grub_free (linep->pos[i]);
a5bd9f6
+	  linep->pos[i] = 0;
a5bd9f6
+	}
a5bd9f6
 
a5bd9f6
       grub_free (next_linep->buf);
a5bd9f6
       grub_memmove (next_linep,
a5bd9f6
@@ -975,24 +912,12 @@ yank (struct screen *screen, int update)
a5bd9f6
 static int
a5bd9f6
 open_line (struct screen *screen, int update)
a5bd9f6
 {
a5bd9f6
-  int saved_y[screen->nterms];
a5bd9f6
-  unsigned i;
a5bd9f6
-
a5bd9f6
-  for (i = 0; i < screen->nterms; i++)
a5bd9f6
-    saved_y[i] = screen->terms[i].y;
a5bd9f6
-
a5bd9f6
   if (! insert_string (screen, "\n", 0))
a5bd9f6
     return 0;
a5bd9f6
 
a5bd9f6
   if (! backward_char (screen, 0))
a5bd9f6
     return 0;
a5bd9f6
 
a5bd9f6
-  for (i = 0; i < screen->nterms; i++)
a5bd9f6
-    {
a5bd9f6
-      screen->terms[i].y = saved_y[i];
a5bd9f6
-      screen->terms[i].y_line_start = screen->terms[i].y;
a5bd9f6
-    }
a5bd9f6
-
a5bd9f6
   if (update)
a5bd9f6
     update_screen_all (screen, screen->line, screen->column, 0, 1, ALL_LINES);
a5bd9f6
 
a5bd9f6
@@ -1303,7 +1228,20 @@ grub_menu_entry_run (grub_menu_entry_t entry)
a5bd9f6
   screen->nterms = 0;
a5bd9f6
   FOR_ACTIVE_TERM_OUTPUTS(term)
a5bd9f6
     screen->nterms++;
a5bd9f6
-  screen->terms = grub_malloc (screen->nterms * sizeof (screen->terms[0]));
a5bd9f6
+
a5bd9f6
+  for (i = 0; i < (unsigned) screen->num_lines; i++)
a5bd9f6
+    {
a5bd9f6
+      grub_free (screen->lines[i].pos);
a5bd9f6
+      screen->lines[i].pos = grub_zalloc (screen->nterms * sizeof (screen->lines[i].pos[0]));
a5bd9f6
+      if (! screen->lines[i].pos)
a5bd9f6
+	{
a5bd9f6
+	  grub_print_error ();
a5bd9f6
+	  grub_errno = GRUB_ERR_NONE;
a5bd9f6
+	  return;
a5bd9f6
+	}
a5bd9f6
+    }
a5bd9f6
+
a5bd9f6
+  screen->terms = grub_zalloc (screen->nterms * sizeof (screen->terms[0]));
a5bd9f6
   if (!screen->terms)
a5bd9f6
     {
a5bd9f6
       grub_print_error ();
a5bd9f6
@@ -1314,9 +1252,7 @@ grub_menu_entry_run (grub_menu_entry_t entry)
a5bd9f6
   FOR_ACTIVE_TERM_OUTPUTS(term)
a5bd9f6
   {
a5bd9f6
     screen->terms[i].term = term;
a5bd9f6
-    screen->terms[i].x = 0;
a5bd9f6
-    screen->terms[i].y = 0;
a5bd9f6
-    screen->terms[i].y_line_start = screen->terms[i].y;
a5bd9f6
+    screen->terms[i].y_line_start = 0;
a5bd9f6
     i++;
a5bd9f6
   }
a5bd9f6
   /* Draw the screen.  */
a5bd9f6
diff --git a/grub-core/normal/term.c b/grub-core/normal/term.c
a5bd9f6
index dc5fdcb..43622be 100644
a5bd9f6
--- a/grub-core/normal/term.c
a5bd9f6
+++ b/grub-core/normal/term.c
a5bd9f6
@@ -34,6 +34,10 @@ struct term_state
a5bd9f6
   int backlog_fixed_tab;
a5bd9f6
   grub_size_t backlog_len;
a5bd9f6
 
a5bd9f6
+  int bidi_stack_depth;
a5bd9f6
+  grub_uint8_t bidi_stack[GRUB_BIDI_MAX_EXPLICIT_LEVEL];
a5bd9f6
+  int invalid_pushes;
a5bd9f6
+
a5bd9f6
   void *free;
a5bd9f6
   int num_lines;
a5bd9f6
   char *term_name;
a5bd9f6
@@ -44,7 +48,9 @@ print_ucs4_real (const grub_uint32_t * str,
a5bd9f6
 		 const grub_uint32_t * last_position,
a5bd9f6
 		 int margin_left, int margin_right,
a5bd9f6
 		 struct grub_term_output *term, int backlog,
a5bd9f6
-		 int dry_run, int fixed_tab);
a5bd9f6
+		 int dry_run, int fixed_tab, unsigned skip_lines,
a5bd9f6
+		 unsigned max_lines,
a5bd9f6
+		 grub_uint32_t contchar, struct grub_term_pos *pos);
a5bd9f6
 
a5bd9f6
 static struct term_state *term_states = NULL;
a5bd9f6
 
a5bd9f6
@@ -243,7 +249,8 @@ grub_puts_terminal (const char *str, struct grub_term_output *term)
a5bd9f6
       return;
a5bd9f6
     }
a5bd9f6
 
a5bd9f6
-  print_ucs4_real (unicode_str, unicode_last_position, 0, 0, term, 0, 0, 0);
a5bd9f6
+  print_ucs4_real (unicode_str, unicode_last_position, 0, 0, term,
a5bd9f6
+		   0, 0, 0, 0, -1, 0, 0);
a5bd9f6
   grub_free (unicode_str);
a5bd9f6
 }
a5bd9f6
 
a5bd9f6
@@ -541,13 +548,25 @@ get_startwidth (struct grub_term_output *term,
a5bd9f6
   return ((term->getxy (term) >> 8) & 0xff) - margin_left;
a5bd9f6
 }
a5bd9f6
 
a5bd9f6
+static void
a5bd9f6
+fill_margin (struct grub_term_output *term, int r)
a5bd9f6
+{
a5bd9f6
+  int sp = (term->getwh (term) >> 8)
a5bd9f6
+    - (term->getxy (term) >> 8) - r;
a5bd9f6
+  if (sp > 0)
a5bd9f6
+    grub_print_spaces (term, sp);
a5bd9f6
+}
a5bd9f6
+
a5bd9f6
 static int
a5bd9f6
 print_ucs4_terminal (const grub_uint32_t * str,
a5bd9f6
 		     const grub_uint32_t * last_position,
a5bd9f6
 		     int margin_left, int margin_right,
a5bd9f6
 		     struct grub_term_output *term,
a5bd9f6
 		     struct term_state *state,
a5bd9f6
-		     int dry_run, int fixed_tab)
a5bd9f6
+		     int dry_run, int fixed_tab, unsigned skip_lines,
a5bd9f6
+		     unsigned max_lines,
a5bd9f6
+		     grub_uint32_t contchar,
a5bd9f6
+		     int primitive_wrap, struct grub_term_pos *pos)
a5bd9f6
 {
a5bd9f6
   const grub_uint32_t *ptr;
a5bd9f6
   grub_ssize_t startwidth = dry_run ? 0 : get_startwidth (term, margin_left);
a5bd9f6
@@ -556,10 +575,40 @@ print_ucs4_terminal (const grub_uint32_t * str,
a5bd9f6
   grub_ssize_t max_width = get_maxwidth (term, margin_left, margin_right);
a5bd9f6
   const grub_uint32_t *line_start = str, *last_space = str - 1;
a5bd9f6
   int lines = 0;
a5bd9f6
+  int i;
a5bd9f6
+  struct term_state local_state;
a5bd9f6
+
a5bd9f6
+  if (!state)
a5bd9f6
+    {
a5bd9f6
+      grub_memset (&local_state, 0, sizeof (local_state));
a5bd9f6
+      state = &local_state;
a5bd9f6
+    }
a5bd9f6
+
a5bd9f6
+  for (i = 0; i < state->bidi_stack_depth; i++)
a5bd9f6
+    putcode_real (state->bidi_stack[i] | (GRUB_UNICODE_LRE & ~0xff),
a5bd9f6
+		  term, fixed_tab);
a5bd9f6
 
a5bd9f6
   for (ptr = str; ptr < last_position; ptr++)
a5bd9f6
     {
a5bd9f6
       grub_ssize_t last_width = 0;
a5bd9f6
+      switch (*ptr)
a5bd9f6
+	{
a5bd9f6
+	case GRUB_UNICODE_LRE:
a5bd9f6
+	case GRUB_UNICODE_RLE:
a5bd9f6
+	case GRUB_UNICODE_LRO:
a5bd9f6
+	case GRUB_UNICODE_RLO:
a5bd9f6
+	  if (state->bidi_stack_depth >= (int) ARRAY_SIZE (state->bidi_stack))
a5bd9f6
+	    state->invalid_pushes++;
a5bd9f6
+	  else
a5bd9f6
+	    state->bidi_stack[state->bidi_stack_depth++] = *ptr;
a5bd9f6
+	  break;
a5bd9f6
+	case GRUB_UNICODE_PDF:
a5bd9f6
+	  if (state->invalid_pushes)
a5bd9f6
+	    state->invalid_pushes--;
a5bd9f6
+	  else if (state->bidi_stack_depth)
a5bd9f6
+	    state->bidi_stack_depth--;
a5bd9f6
+	  break;
a5bd9f6
+	}
a5bd9f6
       if (grub_unicode_get_comb_type (*ptr) == GRUB_UNICODE_COMB_NONE)
a5bd9f6
 	{
a5bd9f6
 	  struct grub_unicode_glyph c = {
a5bd9f6
@@ -569,10 +618,16 @@ print_ucs4_terminal (const grub_uint32_t * str,
a5bd9f6
 	    .combining = 0
a5bd9f6
 	  };
a5bd9f6
 	  c.base = *ptr;
a5bd9f6
+	  if (pos)
a5bd9f6
+	    {
a5bd9f6
+	      pos[ptr - str].x = line_width;
a5bd9f6
+	      pos[ptr - str].y = lines;
a5bd9f6
+	      pos[ptr - str].valid = 1;
a5bd9f6
+	    }
a5bd9f6
 	  line_width += last_width = grub_term_getcharwidth (term, &c);
a5bd9f6
 	}
a5bd9f6
 
a5bd9f6
-      if (*ptr == ' ')
a5bd9f6
+      if (*ptr == ' ' && !primitive_wrap)
a5bd9f6
 	{
a5bd9f6
 	  lastspacewidth = line_width;
a5bd9f6
 	  last_space = ptr;
a5bd9f6
@@ -581,6 +636,13 @@ print_ucs4_terminal (const grub_uint32_t * str,
a5bd9f6
       if (line_width > max_width || *ptr == '\n')
a5bd9f6
 	{
a5bd9f6
 	  const grub_uint32_t *ptr2;
a5bd9f6
+	  int wasn = (*ptr == '\n');
a5bd9f6
+
a5bd9f6
+	  if (wasn)
a5bd9f6
+	    {
a5bd9f6
+	      state->bidi_stack_depth = 0;
a5bd9f6
+	      state->invalid_pushes = 0;
a5bd9f6
+	    }
a5bd9f6
 
a5bd9f6
 	  if (line_width > max_width && last_space > line_start)
a5bd9f6
 	    ptr = last_space;
a5bd9f6
@@ -595,7 +657,7 @@ print_ucs4_terminal (const grub_uint32_t * str,
a5bd9f6
 
a5bd9f6
 	  lines++;
a5bd9f6
 
a5bd9f6
-	  if (!dry_run)
a5bd9f6
+	  if (!skip_lines && !dry_run)
a5bd9f6
 	    {
a5bd9f6
 	      for (ptr2 = line_start; ptr2 < ptr; ptr2++)
a5bd9f6
 		{
a5bd9f6
@@ -608,9 +670,12 @@ print_ucs4_terminal (const grub_uint32_t * str,
a5bd9f6
 		  putcode_real (*ptr2, term, fixed_tab);
a5bd9f6
 		}
a5bd9f6
 
a5bd9f6
-	      grub_print_spaces (term, margin_right);
a5bd9f6
+	      if (!wasn && contchar)
a5bd9f6
+		putcode_real (contchar, term, fixed_tab);
a5bd9f6
+	      fill_margin (term, contchar ? margin_right : 1);
a5bd9f6
+
a5bd9f6
 	      grub_putcode ('\n', term);
a5bd9f6
-	      if (state && ++state->num_lines
a5bd9f6
+	      if (state != &local_state && ++state->num_lines
a5bd9f6
 		  >= (grub_ssize_t) grub_term_height (term) - 2)
a5bd9f6
 		{
a5bd9f6
 		  state->backlog_ucs4 = (ptr == last_space || *ptr == '\n') 
a5bd9f6
@@ -622,17 +687,42 @@ print_ucs4_terminal (const grub_uint32_t * str,
a5bd9f6
 	    }
a5bd9f6
 
a5bd9f6
 	  line_width -= lastspacewidth;
a5bd9f6
-	  if (!dry_run)
a5bd9f6
-	    grub_print_spaces (term, margin_left);
a5bd9f6
 	  if (ptr == last_space || *ptr == '\n')
a5bd9f6
 	    ptr++;
a5bd9f6
 	  line_start = ptr;
a5bd9f6
+
a5bd9f6
+	  if (skip_lines)
a5bd9f6
+	    skip_lines--;
a5bd9f6
+	  else if (max_lines != (unsigned) -1)
a5bd9f6
+	    {
a5bd9f6
+	      max_lines--;
a5bd9f6
+	      if (!max_lines)
a5bd9f6
+		break;
a5bd9f6
+	    }
a5bd9f6
+	  if (!skip_lines && !dry_run)
a5bd9f6
+	    {
a5bd9f6
+	      if (!contchar)
a5bd9f6
+		grub_print_spaces (term, margin_left);
a5bd9f6
+	      else
a5bd9f6
+		grub_term_gotoxy (term, margin_left,
a5bd9f6
+				  grub_term_getxy (term) & 0xff);
a5bd9f6
+	      for (i = 0; i < state->bidi_stack_depth; i++)
a5bd9f6
+		putcode_real (state->bidi_stack[i] | (GRUB_UNICODE_LRE & ~0xff),
a5bd9f6
+			      term, fixed_tab);
a5bd9f6
+	    }
a5bd9f6
 	}
a5bd9f6
     }
a5bd9f6
 
a5bd9f6
+  if (pos)
a5bd9f6
+    {
a5bd9f6
+      pos[ptr - str].x = line_width;
a5bd9f6
+      pos[ptr - str].y = lines;
a5bd9f6
+      pos[ptr - str].valid = 1;
a5bd9f6
+    }
a5bd9f6
+
a5bd9f6
   if (line_start < last_position)
a5bd9f6
     lines++;
a5bd9f6
-  if (!dry_run)
a5bd9f6
+  if (!dry_run && !skip_lines && max_lines)
a5bd9f6
     {
a5bd9f6
       const grub_uint32_t *ptr2;
a5bd9f6
       for (ptr2 = line_start; ptr2 < last_position; ptr2++)
a5bd9f6
@@ -717,7 +807,8 @@ print_backlog (struct grub_term_output *term,
a5bd9f6
       ret = print_ucs4_terminal (state->backlog_ucs4,
a5bd9f6
 				 state->backlog_ucs4 + state->backlog_len,
a5bd9f6
 				 margin_left, margin_right, term, state, 0,
a5bd9f6
-				 state->backlog_fixed_tab);
a5bd9f6
+				 state->backlog_fixed_tab, 0, -1, 0, 0,
a5bd9f6
+				 0);
a5bd9f6
       if (!ret)
a5bd9f6
 	{
a5bd9f6
 	  grub_free (state->free);
a5bd9f6
@@ -753,17 +844,28 @@ print_ucs4_real (const grub_uint32_t * str,
a5bd9f6
 		 const grub_uint32_t * last_position,
a5bd9f6
 		 int margin_left, int margin_right,
a5bd9f6
 		 struct grub_term_output *term, int backlog,
a5bd9f6
-		 int dry_run, int fixed_tab)
a5bd9f6
+		 int dry_run, int fixed_tab, unsigned skip_lines,
a5bd9f6
+		 unsigned max_lines,
a5bd9f6
+		 grub_uint32_t contchar, struct grub_term_pos *pos)
a5bd9f6
 {
a5bd9f6
   struct term_state *state = NULL;
a5bd9f6
 
a5bd9f6
   if (!dry_run)
a5bd9f6
     {
a5bd9f6
+      int xy;
a5bd9f6
       if (backlog)
a5bd9f6
 	state = find_term_state (term);
a5bd9f6
 
a5bd9f6
-      if (((term->getxy (term) >> 8) & 0xff) < margin_left)
a5bd9f6
-	grub_print_spaces (term, margin_left - ((term->getxy (term) >> 8) & 0xff));
a5bd9f6
+      xy = term->getxy (term);
a5bd9f6
+      
a5bd9f6
+      if (((xy >> 8) & 0xff) < margin_left)
a5bd9f6
+	{
a5bd9f6
+	  if (!contchar)
a5bd9f6
+	    grub_print_spaces (term, margin_left - ((xy >> 8) & 0xff));
a5bd9f6
+	  else
a5bd9f6
+	    grub_term_gotoxy (term, margin_left,
a5bd9f6
+			      xy & 0xff);
a5bd9f6
+	}
a5bd9f6
     }
a5bd9f6
 
a5bd9f6
   if ((term->flags & GRUB_TERM_CODE_TYPE_MASK) 
a5bd9f6
@@ -773,7 +875,10 @@ print_ucs4_real (const grub_uint32_t * str,
a5bd9f6
     {
a5bd9f6
       grub_ssize_t visual_len;
a5bd9f6
       struct grub_unicode_glyph *visual;
a5bd9f6
+      grub_ssize_t visual_len_show;
a5bd9f6
+      struct grub_unicode_glyph *visual_show;
a5bd9f6
       int ret;
a5bd9f6
+      struct grub_unicode_glyph *vptr;
a5bd9f6
 
a5bd9f6
       auto grub_ssize_t getcharwidth (const struct grub_unicode_glyph *c);
a5bd9f6
       grub_ssize_t getcharwidth (const struct grub_unicode_glyph *c)
a5bd9f6
@@ -787,27 +892,45 @@ print_ucs4_real (const grub_uint32_t * str,
a5bd9f6
 							      margin_left,
a5bd9f6
 							      margin_right),
a5bd9f6
 						get_startwidth (term, 
a5bd9f6
-								margin_left));
a5bd9f6
+								margin_left),
a5bd9f6
+						contchar, pos, !!contchar);
a5bd9f6
       if (visual_len < 0)
a5bd9f6
 	{
a5bd9f6
 	  grub_print_error ();
a5bd9f6
 	  return 0;
a5bd9f6
 	}
a5bd9f6
+      visual_show = visual;
a5bd9f6
+      for (; skip_lines && visual_show < visual + visual_len; visual_show++)
a5bd9f6
+	if (visual_show->base == '\n')
a5bd9f6
+	  skip_lines--;
a5bd9f6
+      if (max_lines != (unsigned) -1)
a5bd9f6
+	{
a5bd9f6
+	  for (vptr = visual_show;
a5bd9f6
+	       max_lines && vptr < visual + visual_len; vptr++)
a5bd9f6
+	    if (visual_show->base == '\n')
a5bd9f6
+	      max_lines--;
a5bd9f6
+
a5bd9f6
+	  visual_len_show = vptr - visual_show;	  
a5bd9f6
+	}
a5bd9f6
+      else
a5bd9f6
+	visual_len_show = visual + visual_len - visual_show;
a5bd9f6
+
a5bd9f6
       if (dry_run)
a5bd9f6
 	{
a5bd9f6
-	  struct grub_unicode_glyph *vptr;
a5bd9f6
 	  ret = 0;
a5bd9f6
-	  for (vptr = visual; vptr < visual + visual_len; vptr++)
a5bd9f6
+	  for (vptr = visual_show; vptr < visual_show + visual_len_show; vptr++)
a5bd9f6
 	    if (vptr->base == '\n')
a5bd9f6
 	      ret++;
a5bd9f6
-	  if (visual_len && visual[visual_len - 1].base != '\n')
a5bd9f6
+	  if (visual_len_show && visual[visual_len_show - 1].base != '\n')
a5bd9f6
 	    ret++;
a5bd9f6
 	  grub_free (visual);
a5bd9f6
 	}
a5bd9f6
       else
a5bd9f6
 	{
a5bd9f6
-	  ret = put_glyphs_terminal (visual, visual_len, margin_left,
a5bd9f6
-				     margin_right, term, state, fixed_tab);
a5bd9f6
+	  ret = put_glyphs_terminal (visual_show, visual_len_show, margin_left,
a5bd9f6
+				     contchar ? margin_right : 1,
a5bd9f6
+				     term, state, fixed_tab);
a5bd9f6
+
a5bd9f6
 	  if (!ret)
a5bd9f6
 	    grub_free (visual);
a5bd9f6
 	  else
a5bd9f6
@@ -816,7 +939,22 @@ print_ucs4_real (const grub_uint32_t * str,
a5bd9f6
       return ret;
a5bd9f6
     }
a5bd9f6
   return print_ucs4_terminal (str, last_position, margin_left, margin_right,
a5bd9f6
-			      term, state, dry_run, fixed_tab);
a5bd9f6
+			      term, state, dry_run, fixed_tab, skip_lines,
a5bd9f6
+			      max_lines, contchar, !!contchar, pos);
a5bd9f6
+}
a5bd9f6
+
a5bd9f6
+void
a5bd9f6
+grub_print_ucs4_menu (const grub_uint32_t * str,
a5bd9f6
+		      const grub_uint32_t * last_position,
a5bd9f6
+		      int margin_left, int margin_right,
a5bd9f6
+		      struct grub_term_output *term,
a5bd9f6
+		      int skip_lines, int max_lines,
a5bd9f6
+		      grub_uint32_t contchar,
a5bd9f6
+		      struct grub_term_pos *pos)
a5bd9f6
+{
a5bd9f6
+  print_ucs4_real (str, last_position, margin_left, margin_right,
a5bd9f6
+		   term, 0, 0, 1, skip_lines, max_lines,
a5bd9f6
+		   contchar, pos);
a5bd9f6
 }
a5bd9f6
 
a5bd9f6
 void
a5bd9f6
@@ -826,7 +964,7 @@ grub_print_ucs4 (const grub_uint32_t * str,
a5bd9f6
 		 struct grub_term_output *term)
a5bd9f6
 {
a5bd9f6
   print_ucs4_real (str, last_position, margin_left, margin_right,
a5bd9f6
-		   term, 0, 0, 1);
a5bd9f6
+		   term, 0, 0, 1, 0, -1, 0, 0);
a5bd9f6
 }
a5bd9f6
 
a5bd9f6
 int
a5bd9f6
@@ -836,7 +974,7 @@ grub_ucs4_count_lines (const grub_uint32_t * str,
a5bd9f6
 		       struct grub_term_output *term)
a5bd9f6
 {
a5bd9f6
   return print_ucs4_real (str, last_position, margin_left, margin_right,
a5bd9f6
-			  term, 0, 1, 1);
a5bd9f6
+			  term, 0, 1, 1, 0, -1, 0, 0);
a5bd9f6
 }
a5bd9f6
 
a5bd9f6
 void
a5bd9f6
@@ -886,7 +1024,7 @@ grub_xputs_normal (const char *str)
a5bd9f6
   {
a5bd9f6
     int cur;
a5bd9f6
     cur = print_ucs4_real (unicode_str, unicode_last_position, 0, 0,
a5bd9f6
-			   term, grub_more, 0, 0);
a5bd9f6
+			   term, grub_more, 0, 0, 0, -1, 0, 0);
a5bd9f6
     if (cur)
a5bd9f6
       backlog = 1;
a5bd9f6
   }
a5bd9f6
diff --git a/include/grub/normal.h b/include/grub/normal.h
a5bd9f6
index e88cd26..416faa4 100644
a5bd9f6
--- a/include/grub/normal.h
a5bd9f6
+++ b/include/grub/normal.h
a5bd9f6
@@ -77,6 +77,14 @@ grub_print_ucs4 (const grub_uint32_t * str,
a5bd9f6
 		 const grub_uint32_t * last_position,
a5bd9f6
 		 int margin_left, int margin_right,
a5bd9f6
 		 struct grub_term_output *term);
a5bd9f6
+
a5bd9f6
+void
a5bd9f6
+grub_print_ucs4_menu (const grub_uint32_t * str,
a5bd9f6
+		      const grub_uint32_t * last_position,
a5bd9f6
+		      int margin_left, int margin_right,
a5bd9f6
+		      struct grub_term_output *term,
a5bd9f6
+		      int skip_lines, int max_lines, grub_uint32_t contchar,
a5bd9f6
+		      struct grub_term_pos *pos);
a5bd9f6
 int
a5bd9f6
 grub_ucs4_count_lines (const grub_uint32_t * str,
a5bd9f6
 		       const grub_uint32_t * last_position,
a5bd9f6
diff --git a/include/grub/term.h b/include/grub/term.h
a5bd9f6
index bf4dcb4..39c3d5a 100644
a5bd9f6
--- a/include/grub/term.h
a5bd9f6
+++ b/include/grub/term.h
a5bd9f6
@@ -104,7 +104,7 @@ grub_term_color_state;
a5bd9f6
 #define GRUB_TERM_CODE_TYPE_CP437	                (1 << GRUB_TERM_CODE_TYPE_SHIFT)
a5bd9f6
 /* UTF-8 stream in logical order. Usually used for terminals
a5bd9f6
    which just forward the stream to another computer.  */
a5bd9f6
-#define GRUB_TERM_CODE_TYPE_UTF8_LOGICAL	(2 << GRUB_TERM_CODE_TYPE_SHIFT)
a5bd9f6
+#define GRUB_TERM_CODE_TYPE_UTF8_LOGICAL       	(2 << GRUB_TERM_CODE_TYPE_SHIFT)
a5bd9f6
 /* UTF-8 in visual order. Like UTF-8 logical but for buggy endpoints.  */
a5bd9f6
 #define GRUB_TERM_CODE_TYPE_UTF8_VISUAL	        (3 << GRUB_TERM_CODE_TYPE_SHIFT)
a5bd9f6
 /* Glyph description in visual order.  */
a5bd9f6
@@ -344,7 +344,7 @@ static inline unsigned grub_term_height (struct grub_term_output *term)
a5bd9f6
 static inline unsigned
a5bd9f6
 grub_term_border_width (struct grub_term_output *term)
a5bd9f6
 {
a5bd9f6
-  return grub_term_width (term) - GRUB_TERM_MARGIN * 3 - GRUB_TERM_SCROLL_WIDTH;
a5bd9f6
+  return grub_term_width (term) - GRUB_TERM_MARGIN * 2;
a5bd9f6
 }
a5bd9f6
 
a5bd9f6
 /* The max column number of an entry. The last "-1" is for a
a5bd9f6
@@ -352,7 +352,7 @@ grub_term_border_width (struct grub_term_output *term)
a5bd9f6
 static inline int
a5bd9f6
 grub_term_entry_width (struct grub_term_output *term)
a5bd9f6
 {
a5bd9f6
-  return grub_term_border_width (term) - 2 - GRUB_TERM_MARGIN * 2 - 1;
a5bd9f6
+  return grub_term_border_width (term) - GRUB_TERM_MARGIN * 2 - 1;
a5bd9f6
 }
a5bd9f6
 
a5bd9f6
 static inline grub_uint16_t
a5bd9f6
diff --git a/include/grub/unicode.h b/include/grub/unicode.h
a5bd9f6
index 763e25e..eb5051a 100644
a5bd9f6
--- a/include/grub/unicode.h
a5bd9f6
+++ b/include/grub/unicode.h
a5bd9f6
@@ -139,6 +139,7 @@ struct grub_unicode_glyph
a5bd9f6
   grub_uint16_t variant:9;
a5bd9f6
   grub_uint8_t attributes:5;
a5bd9f6
   grub_size_t ncomb;
a5bd9f6
+  grub_size_t orig_pos;
a5bd9f6
   struct grub_unicode_combining {
a5bd9f6
     grub_uint32_t code;
a5bd9f6
     enum grub_comb_type type;
a5bd9f6
@@ -186,6 +187,13 @@ enum
a5bd9f6
     GRUB_UNICODE_THAANA_SUKUN              = 0x07b0,
a5bd9f6
     GRUB_UNICODE_ZWNJ                      = 0x200c,
a5bd9f6
     GRUB_UNICODE_ZWJ                       = 0x200d,
a5bd9f6
+    GRUB_UNICODE_LRM                       = 0x200e,
a5bd9f6
+    GRUB_UNICODE_RLM                       = 0x200f,
a5bd9f6
+    GRUB_UNICODE_LRE                       = 0x202a,
a5bd9f6
+    GRUB_UNICODE_RLE                       = 0x202b,
a5bd9f6
+    GRUB_UNICODE_PDF                       = 0x202c,
a5bd9f6
+    GRUB_UNICODE_LRO                       = 0x202d,
a5bd9f6
+    GRUB_UNICODE_RLO                       = 0x202e,
a5bd9f6
     GRUB_UNICODE_LEFTARROW                 = 0x2190,
a5bd9f6
     GRUB_UNICODE_UPARROW                   = 0x2191,
a5bd9f6
     GRUB_UNICODE_RIGHTARROW                = 0x2192,
a5bd9f6
@@ -222,13 +230,21 @@ extern struct grub_unicode_bidi_pair grub_unicode_bidi_pairs[];
a5bd9f6
 /*  Unicode mandates an arbitrary limit.  */
a5bd9f6
 #define GRUB_BIDI_MAX_EXPLICIT_LEVEL 61
a5bd9f6
 
a5bd9f6
+struct grub_term_pos
a5bd9f6
+{
a5bd9f6
+  unsigned valid:1;
a5bd9f6
+  unsigned x:15, y:16;
a5bd9f6
+};
a5bd9f6
+
a5bd9f6
 grub_ssize_t
a5bd9f6
 grub_bidi_logical_to_visual (const grub_uint32_t *logical,
a5bd9f6
 			     grub_size_t logical_len,
a5bd9f6
 			     struct grub_unicode_glyph **visual_out,
a5bd9f6
 			     grub_ssize_t (*getcharwidth) (const struct grub_unicode_glyph *visual),
a5bd9f6
 			     grub_size_t max_width,
a5bd9f6
-			     grub_size_t start_width);
a5bd9f6
+			     grub_size_t start_width, grub_uint32_t codechar,
a5bd9f6
+			     struct grub_term_pos *pos,
a5bd9f6
+			     int primitive_wrap);
a5bd9f6
 
a5bd9f6
 enum grub_comb_type
a5bd9f6
 grub_unicode_get_comb_type (grub_uint32_t c);
a5bd9f6
@@ -275,4 +291,8 @@ grub_unicode_mirror_code (grub_uint32_t in);
a5bd9f6
 grub_uint32_t
a5bd9f6
 grub_unicode_shape_code (grub_uint32_t in, grub_uint8_t attr);
a5bd9f6
 
a5bd9f6
+const grub_uint32_t *
a5bd9f6
+grub_unicode_get_comb_end (const grub_uint32_t *end, 
a5bd9f6
+			   const grub_uint32_t *cur);
a5bd9f6
+
a5bd9f6
 #endif
a5bd9f6
-- 
a5bd9f6
1.8.1.4
a5bd9f6