*** empty log message ***
[m17n/m17n-lib.git] / src / draw.c
index 54fda12..1d5ced0 100644 (file)
@@ -80,7 +80,7 @@
 static MSymbol M_glyph_string;
 
 /* Special scripts */
-static MSymbol Mlatin, Minherited;
+static MSymbol Minherited;
 /* Special categories */
 static MSymbol McatCc, McatCf;
 
@@ -103,8 +103,7 @@ visual_order (MGlyphString *gstring)
   MGlyph *g;
   int i;
 #ifdef HAVE_FRIBIDI
-  FriBidiCharType base = (gstring->control.orientation_reversed
-                         ? FRIBIDI_TYPE_RTL : FRIBIDI_TYPE_LTR);
+  FriBidiCharType base = bidi_sensitive ? FRIBIDI_TYPE_RTL : FRIBIDI_TYPE_LTR;
   FriBidiChar *logical = alloca (sizeof (FriBidiChar) * len);
   FriBidiChar *visual;
   FriBidiStrIndex *indices;
@@ -117,15 +116,22 @@ visual_order (MGlyphString *gstring)
 
   for (g = MGLYPH (1), i = 0; g->type != GLYPH_ANCHOR; g++, i++)
     {
-      MSymbol bidi = (MSymbol) mchar_get_prop (g->c, Mbidi_category);
-
-      if (bidi == MbidiR || bidi == MbidiAL
-         || bidi == MbidiRLE || bidi == MbidiRLO)
+      if (! bidi_sensitive
+#ifndef HAVE_FRIBIDI
+         || 1
+#endif /* not HAVE_FRIBIDI */
+         )
        {
-         bidi_sensitive = 1;
+         MSymbol bidi = (MSymbol) mchar_get_prop (g->c, Mbidi_category);
+
+         if (bidi == MbidiR || bidi == MbidiAL
+             || bidi == MbidiRLE || bidi == MbidiRLO)
+           {
+             bidi_sensitive = 1;
 #ifndef HAVE_FRIBIDI
-         levels[i] = 1;
+             levels[i] = 1;
 #endif /* not HAVE_FRIBIDI */
+           }
        }
       logical[i] = g->c;
     }
@@ -159,14 +165,14 @@ visual_order (MGlyphString *gstring)
     }
 #endif /* not HAVE_FRIBIDI */
 
-  for (i = 0; i < len; i++)
+  for (i = 0; i < len;)
     {
+      /* Index into gstring->glyphs plus 1 for GLYPHS[i].  */
       int j = indices[i];
+      /* Length of grapheme-cluster */
+      int seglen;
 
-      g = MGLYPH (j + 1);
-      if (i != j)
-       *g = glyphs[i];
-      g->bidi_level = levels[i];
+      g = glyphs + i;
 #ifdef HAVE_FRIBIDI
       if (visual[j] != logical[i])
        {
@@ -176,6 +182,18 @@ visual_order (MGlyphString *gstring)
            g->code = mfont__encode_char (g->rface->rfont, g->c);
        }
 #endif /* HAVE_FRIBIDI */
+      g->bidi_level = levels[i];
+      for (seglen = 1, g++;
+          i + seglen < len && (glyphs[i].pos == glyphs[i + seglen].pos
+                               || glyphs[i + seglen].combining_code);
+          seglen++, g++)
+       {
+         g->bidi_level = levels[i];
+         if (indices[i + seglen] < j)
+           j = indices[i + seglen];
+       }
+      memcpy (MGLYPH (j + 1), glyphs + i, sizeof (MGlyph) * seglen);
+      i += seglen;
     }
 }
 
@@ -205,9 +223,9 @@ reorder_combining_chars (MGlyphString *gstring, int from, int to)
 /** Scan M-text MT from FROM to TO, and compose glyphs in GSTRING for
     displaying them on FRAME.
 
-    This function fills members <type>, <rface>, <c>, <pos>, <to>,
-    <code> of glyphs.  The other members are filled by
-    layout_glyph_string.  */
+    This function fills these members:
+      pos, to, c, code, rface, bidi_level, categories, type, combining_code
+    The other members are filled by layout_glyph_string.  */
 
 static void
 compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
@@ -215,51 +233,107 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
 {
   MRealizedFace *default_rface = frame->rface;
   int stop, face_change, language_change, charset_change;
-  MGlyph g_tmp, *g;
+  MGlyph g_tmp, *g, *last_g;
   int pos;
   MSymbol language = Mnil, script = Mnil, charset = Mnil;
   MSymbol non_latin_script = Mnil;
   MRealizedFace *rface = default_rface;
+  MRealizedFont *rfont;
   int size = gstring->control.fixed_width;
   int i;
-  int last;
 
   MLIST_RESET (gstring);
   gstring->from = from;
 
-  /* At first generate glyphs while using the member <enabled> as a
-     flag for rface re-checking.  */
+  /* At first generate glyphs with <pos>, <to>, <c>, <type>,
+     <category> and <rface> members.*/
   INIT_GLYPH (g_tmp);
 
   /** Put anchor glyphs at the head and tail.  */
   g_tmp.type = GLYPH_ANCHOR;
   g_tmp.pos = g_tmp.to = from;
-  g_tmp.c = 0;
   APPEND_GLYPH (gstring, g_tmp);
-
-  stop = face_change = charset_change = language_change = pos = from;
-  last = 0;
+  stop = face_change = pos = from;
   while (1)
     {
       int c;
-      MSymbol this_script;
+      MSymbol category;
+
+      if (pos == stop)
+       {
+         if (pos == to)
+           break;
+         if (pos == face_change)
+           {
+             MFace *faces[64];
+             int num = mtext_get_prop_values (mt, pos, Mface,
+                                              (void **) faces, 64);
+
+             mtext_prop_range (mt, Mface, pos, NULL, &face_change, 1);
+             if (face_change == mtext_nchars (mt))
+               face_change++;
+             rface = (num > 0 ? mface__realize (frame, faces, num, size)
+                      : default_rface);
+           }
+         stop = to;
+         if (stop > face_change)
+           stop = face_change;         
+       }
 
       if (pos < mtext_nchars (mt))
        c = mtext_ref_char (mt, pos);
       else
        c = '\n';
-      g_tmp.category = mchar_get_prop (c, Mcategory);
-      if (c < 0x100)
+      g_tmp.type
+       = (c == ' ' || c == '\n' || c == '\t') ? GLYPH_SPACE : GLYPH_CHAR;
+      g_tmp.c = c;
+      g_tmp.pos = pos++;
+      g_tmp.to = pos;
+      g_tmp.rface = rface;
+      category = mchar_get_prop (c, Mcategory);
+      if (category == McatCf)
+       g_tmp.category = GLYPH_CATEGORY_FORMATTER;
+      else if (category != Mnil && MSYMBOL_NAME (category)[0] == 'M')
+       g_tmp.category = GLYPH_CATEGORY_MODIFIER;
+      else
+       g_tmp.category = GLYPH_CATEGORY_NORMAL;
+      
+      if ((c <= ' ' || c == 127) && g_tmp.type == GLYPH_CHAR)
        {
-         /* Short cut for the obvious case.  */
-         g_tmp.type = (c == ' ' || c == '\n' || c == '\t'
-                       ? GLYPH_SPACE : GLYPH_CHAR);
-         this_script = (MSYMBOL_NAME (g_tmp.category)[0] == 'L'
-                        ? Mlatin : Mnil);
+         MGlyph ctrl[2];
+
+         ctrl[0] = ctrl[1] = g_tmp;
+         ctrl[0].c = '^';
+         ctrl[1].c = c < ' ' ? c + 0x40 : '?';
+         APPEND_GLYPH (gstring, ctrl[0]);
+         APPEND_GLYPH (gstring, ctrl[1]);
        }
       else
+       APPEND_GLYPH (gstring, g_tmp);
+      if (c == '\n' && gstring->control.two_dimensional)
+       break;
+    }
+  /* Append an anchor glyph.  */
+  INIT_GLYPH (g_tmp);
+  g_tmp.type = GLYPH_ANCHOR;
+  g_tmp.pos = g_tmp.to = pos;
+  APPEND_GLYPH (gstring, g_tmp);
+  gstring->to = pos;
+
+  /* The next loop is to change each <rface> member for non-ASCII
+     characters if necessary.  */
+  stop = charset_change = language_change = from;
+  rfont = default_rface->rfont;
+  for (last_g = g = MGLYPH (1); g->type != GLYPH_ANCHOR; g++)
+    {
+      int c = g->c;
+      MSymbol this_script;
+
+      if (c < 0x100)
+       /* Short cut for the obvious case.  */
+       this_script = Mlatin;
+      else
        {
-         g_tmp.type = GLYPH_CHAR;
          this_script = (MSymbol) mchar_get_prop (c, Mscript);
          if (this_script == Minherited || this_script == Mnil)
            this_script = script;
@@ -269,12 +343,12 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
            {
              /* Search forward for a character that explicitly
                 specifies a non-latin script.  */
-             int c1;
              MSymbol sym;
+             MGlyph *g1;
 
-             for (i = pos + 1; i < to; i++)
-               if ((c1 = mtext_ref_char (mt, i)) >= 0x100
-                   && (sym = mchar_get_prop (c1, Mscript)) != Mnil
+             for (g1 = g + 1; g1->type != GLYPH_ANCHOR; g1++)
+               if (g1->c >= 0x100
+                   && (sym = mchar_get_prop (g1->c, Mscript)) != Mnil
                    && sym != Minherited)
                  {
                    this_script = sym;
@@ -283,21 +357,16 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
            }
        }
 
-      if (pos == stop || script != this_script
-         || MGLYPH (last)->type != g_tmp.type)
+      pos = g->pos;
+      if (pos == stop || script != this_script || g->rface->rfont != rfont)
        {
-         g = MGLYPH (last);
-         if (g->type != GLYPH_ANCHOR)
-           while (g < gstring->glyphs + gstring->used)
-             g = mface__for_chars (script == Mnil ? Mlatin : script,
-                                   language, charset,
-                                   g, gstring->glyphs + gstring->used, size);
-         if (pos == to)
-           break;
-         last = gstring->used;
+         while (last_g < g)
+           last_g = mface__for_chars (script, language, charset,
+                                      last_g, g, size);
          script = this_script;
          if (script != Mnil && script != Mlatin)
            non_latin_script = script;
+         rfont = g->rface->ascii_rface->rfont;
          if (pos == stop)
            {
              if (pos < mtext_nchars (mt) && pos == language_change)
@@ -312,63 +381,20 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
                  mtext_prop_range (mt, Mcharset, pos, NULL,
                                    &charset_change, 0);
                }
-             if (pos < mtext_nchars (mt) && pos == face_change)
-               {
-                 MFace *faces[64];
-                 int num = mtext_get_prop_values (mt, pos, Mface,
-                                                  (void **) faces, 64);
-
-                 mtext_prop_range (mt, Mface, pos, NULL, &face_change, 1);
-                 rface = (num > 0
-                          ? mface__realize (frame, faces, num,
-                                            language, charset, size)
-                          : default_rface);
-               }
              stop = to;
              if (stop > language_change)
                stop = language_change;
              if (stop > charset_change)
                stop = charset_change;
-             if (face_change < stop)
-               stop = face_change;             
            }
        }
-
-      g_tmp.c = c;
-      g_tmp.pos = pos++;
-      g_tmp.to = pos;
-      g_tmp.rface = rface;
-      
-      if ((c <= 32 || c == 127) && g_tmp.type == GLYPH_CHAR)
-       {
-         MGlyph ctrl[2];
-
-         ctrl[0] = ctrl[1] = g_tmp;
-         ctrl[0].c = '^';
-         ctrl[1].c = c < ' ' ? c + 0x40 : '?';
-         mface__for_chars (Mlatin, language, charset, ctrl, ctrl + 2, size);
-         APPEND_GLYPH (gstring, ctrl[0]);
-         APPEND_GLYPH (gstring, ctrl[1]);
-       }
-      else
-       APPEND_GLYPH (gstring, g_tmp);
-      if (c == '\n'
-         && gstring->control.two_dimensional)
-       break;
     }
+  while (last_g < g)
+    last_g = mface__for_chars (script, language, charset, last_g, g, size);
 
-  /* Append an anchor glyph.  */
-  g_tmp.type = GLYPH_ANCHOR;
-  g_tmp.c = 0;
-  g_tmp.code = MCHAR_INVALID_CODE;
-  g_tmp.pos = g_tmp.to = pos;
-  g_tmp.rface = NULL;
-  APPEND_GLYPH (gstring, g_tmp);
-
-  gstring->to = pos;
-
-  /* Next, run FLT if necessary.  */
-  for (i = 1, g = MGLYPH (i); g->type != GLYPH_ANCHOR;)
+  /* The next loop is to run FLT or perform the default combining if
+     necessary.  */
+  for (i = 1, g = MGLYPH (1); g->type != GLYPH_ANCHOR;)
     {
       MGlyph *this = g;
 
@@ -383,7 +409,7 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
 
              for (prev = MGLYPH (start - 1);
                   (prev->type == GLYPH_CHAR
-                   && prev->category == McatCf
+                   && prev->category == GLYPH_CATEGORY_FORMATTER
                    && (code = mfont__encode_char (this->rface->rfont, prev->c)
                        != MCHAR_INVALID_CODE));
                   start--, prev--)
@@ -392,7 +418,7 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
              for (g++;
                   (g->type == GLYPH_CHAR
                    && (g->rface->rfont == this->rface->rfont
-                       || (g->category == McatCf
+                       || (g->category == GLYPH_CATEGORY_FORMATTER
                            && ((code = mfont__encode_char (this->rface->rfont,
                                                            g->c))
                                != MCHAR_INVALID_CODE))));
@@ -408,8 +434,7 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
            {
              while (this->type == GLYPH_CHAR
                     && this->c >= 0x100
-                    && this->category
-                    && MSYMBOL_NAME (this->category)[0] == 'M'
+                    && this->category == GLYPH_CATEGORY_MODIFIER
                     && this->rface->rfont
                     && this->rface->rfont->layouter == Mnil)
                {
@@ -487,18 +512,22 @@ combining_code_from_class (int class)
 }
 
 
+typedef struct {
+  int width, lbearing, rbearing;
+} MSubTextExtents;
+
 static void
-layout_glyphs (MFrame *frame, MGlyphString *gstring, int from, int to)
+layout_glyphs (MFrame *frame, MGlyphString *gstring, int from, int to,
+              MSubTextExtents *extents)
 {
   int g_physical_ascent, g_physical_descent;
-  int g_width, g_lbearing, g_rbearing;
   MGlyph *g = MGLYPH (from);
   MGlyph *last_g = MGLYPH (to);
   int i;
 
   g_physical_ascent = gstring->physical_ascent;
   g_physical_descent = gstring->physical_descent;
-  g_width = g_lbearing = g_rbearing = 0;
+  extents->width = extents->lbearing = extents->rbearing = 0;
 
   for (i = from; i < to;)
     {
@@ -513,21 +542,6 @@ layout_glyphs (MFrame *frame, MGlyphString *gstring, int from, int to)
        }
     }
 
-  while (g < last_g)
-    {
-      MGlyph *base = g++;
-
-      if (base->combining_code && (base->bidi_level % 2))
-       {
-         MGlyph *g1 = base, *g2, temp;
-
-         while (g->combining_code)
-           g++;
-         for (g2 = g; g1 < g2; g1++, g2--)
-           temp = *g1, *g1 = *g2, *g2 = temp;
-         g++;
-       }
-    }
   g = MGLYPH (from);
   while (g < last_g)
     {
@@ -536,7 +550,7 @@ layout_glyphs (MFrame *frame, MGlyphString *gstring, int from, int to)
       int size = rfont->font.property[MFONT_SIZE];
       int width, lbearing, rbearing;
 
-      if (g == last_g || ! g->combining_code || g->otf_encoded)
+      if (g == last_g || ! g->combining_code)
        {
          /* No combining.  */
          if (base->width == 0 && ! base->left_padding && ! base->right_padding
@@ -587,48 +601,53 @@ layout_glyphs (MFrame *frame, MGlyphString *gstring, int from, int to)
 
          while (g != last_g && g->combining_code)
            {
-             int combining_code, base_x, base_y, add_x, add_y, off_x, off_y;
-
-             combining_code = g->combining_code;
-             if (COMBINING_BY_CLASS_P (combining_code))
-               g->combining_code = combining_code
-                 = combining_code_from_class (COMBINING_CODE_CLASS
-                                              (combining_code));
-
-             rfont = g->rface->rfont;
-             size = rfont->font.property[MFONT_SIZE];
-             off_x = (size * (COMBINING_CODE_OFF_X (combining_code) - 128)
-                      / 1000);
-             off_y = (size * (COMBINING_CODE_OFF_Y (combining_code) - 128)
-                      / 1000);
-             base_x = COMBINING_CODE_BASE_X (combining_code);
-             base_y = COMBINING_CODE_BASE_Y (combining_code);
-             add_x = COMBINING_CODE_ADD_X (combining_code);
-             add_y = COMBINING_CODE_ADD_Y (combining_code);
+             int combining_code = g->combining_code;
 
              if (begin > g->pos)
                begin = g->pos;
              else if (end < g->to)
                end = g->to;
                
-             g->xoff = left + (width * base_x - g->width * add_x) / 2 + off_x;
-             if (g->xoff < left)
-               left = g->xoff;
-             if (g->xoff + g->width > right)
-               right = g->xoff + g->width;
-             width = right - left;
+             if (! COMBINING_PRECOMPUTED_P (combining_code))
+               {
+                 int base_x, base_y, add_x, add_y, off_x, off_y;
+
+                 if (COMBINING_BY_CLASS_P (combining_code))
+                   g->combining_code = combining_code
+                     = combining_code_from_class (COMBINING_CODE_CLASS
+                                                  (combining_code));
+
+                 rfont = g->rface->rfont;
+                 size = rfont->font.property[MFONT_SIZE];
+                 off_x = (size * (COMBINING_CODE_OFF_X (combining_code) - 128)
+                          / 1000);
+                 off_y = (size * (COMBINING_CODE_OFF_Y (combining_code) - 128)
+                          / 1000);
+                 base_x = COMBINING_CODE_BASE_X (combining_code);
+                 base_y = COMBINING_CODE_BASE_Y (combining_code);
+                 add_x = COMBINING_CODE_ADD_X (combining_code);
+                 add_y = COMBINING_CODE_ADD_Y (combining_code);
+
+                 g->xoff = left + (width * base_x - g->width * add_x) / 2 + off_x;
+                 if (g->xoff < left)
+                   left = g->xoff;
+                 if (g->xoff + g->width > right)
+                   right = g->xoff + g->width;
+                 width = right - left;
+
+                 if (base_y < 3)
+                   g->yoff = top + height * base_y / 2;
+                 else
+                   g->yoff = 0;
+                 if (add_y < 3)
+                   g->yoff -= (g->ascent + g->descent) * add_y / 2 - g->ascent;
+                 g->yoff -= off_y;
+               }
+
              if (g->xoff + g->lbearing < left + lbearing)
                lbearing = g->xoff + g->lbearing - left;
              if (g->xoff + g->rbearing > left + rbearing)
                rbearing = g->xoff + g->rbearing - left;
-
-             if (base_y < 3)
-               g->yoff = top + height * base_y / 2;
-             else
-               g->yoff = 0;
-             if (add_y < 3)
-               g->yoff -= (g->ascent + g->descent) * add_y / 2 - g->ascent;
-             g->yoff -= off_y;
              if (g->yoff - g->ascent < top)
                top = g->yoff - g->ascent;
              if (g->yoff + g->descent > bottom)
@@ -668,16 +687,13 @@ layout_glyphs (MFrame *frame, MGlyphString *gstring, int from, int to)
 
       g_physical_ascent = MAX (g_physical_ascent, base->ascent);
       g_physical_descent = MAX (g_physical_descent, base->descent);
-      g_lbearing = MIN (g_lbearing, g_width + lbearing);
-      g_rbearing = MAX (g_rbearing, g_width + rbearing);
-      g_width += base->width;
+      extents->lbearing = MIN (extents->lbearing, extents->width + lbearing);
+      extents->rbearing = MAX (extents->rbearing, extents->width + rbearing);
+      extents->width += base->width;
     }
 
   gstring->physical_ascent = g_physical_ascent;
   gstring->physical_descent = g_physical_descent;
-  gstring->sub_width = g_width;
-  gstring->sub_lbearing = g_lbearing;
-  gstring->sub_rbearing = g_rbearing;
 }
 
 
@@ -763,7 +779,7 @@ layout_glyph_string (MFrame *frame, MGlyphString *gstring)
            }
        }
 
-      if (g->category == McatCf && ignore_formatting_char)
+      if (g->category == GLYPH_CATEGORY_FORMATTER && ignore_formatting_char)
        g->type = GLYPH_SPACE;
 
       if (g->type == GLYPH_CHAR)
@@ -778,18 +794,24 @@ layout_glyph_string (MFrame *frame, MGlyphString *gstring)
                || box != g->rface->box
                || ((fromg->code == MCHAR_INVALID_CODE)
                    != (g->code == MCHAR_INVALID_CODE))
-               || (g->category == McatCf && ignore_formatting_char))
+               || (g->category == GLYPH_CATEGORY_FORMATTER
+                   && ignore_formatting_char))
              break;
          if (rfont && fromg->code != MCHAR_INVALID_CODE)
            {
              int extra_width;
              int to = GLYPH_INDEX (g);
+             MSubTextExtents extents;
 
-             layout_glyphs (frame, gstring, from, to);
-             extra_width = - gstring->sub_lbearing;
+             layout_glyphs (frame, gstring, from, to, &extents);
+             extra_width = - extents.lbearing;
              if (extra_width > 0
-                 && (GLYPH_INDEX (g) > 1
-                     || (! control->orientation_reversed && control->align_head)))
+                 && ! control->disable_overlapping_adjustment
+                 && (! control->orientation_reversed
+                     ? ((to > 1 || control->align_head)
+                        && g->type != GLYPH_ANCHOR)
+                     : (((g->type && GLYPH_ANCHOR) || control->align_head)
+                        && to > 1)))
                {
                  g = MGLYPH (from);
                  pad = *g;
@@ -800,9 +822,9 @@ layout_glyph_string (MFrame *frame, MGlyphString *gstring)
                  pad.left_padding = 1;
                  INSERT_GLYPH (gstring, from, pad);
                  to++;
-                 gstring->sub_lbearing = 0;
-                 gstring->sub_width += extra_width;
-                 gstring->sub_rbearing += extra_width;
+                 extents.lbearing = 0;
+                 extents.width += extra_width;
+                 extents.rbearing += extra_width;
 
                  g = MGLYPH (from - 1);
                  if (g->type == GLYPH_SPACE)
@@ -830,8 +852,9 @@ layout_glyph_string (MFrame *frame, MGlyphString *gstring)
                }
 
              g = MGLYPH (to);
-             extra_width = gstring->sub_rbearing - gstring->sub_width;
+             extra_width = extents.rbearing - extents.width;
              if (extra_width > 0
+                 && ! control->disable_overlapping_adjustment
                  && (GLYPH_INDEX (g) < gstring->used - 1
                      || (control->orientation_reversed && control->align_head)))
                {
@@ -843,17 +866,19 @@ layout_glyph_string (MFrame *frame, MGlyphString *gstring)
                      pad.lbearing = 0;
                      pad.width = pad.rbearing = extra_width;
                      INSERT_GLYPH (gstring, to, pad);
+                     to++;
+                     g = MGLYPH (to);
                    }
                  else
                    g[-1].width += extra_width;
-                 gstring->sub_width += extra_width;
+                 extents.width += extra_width;
                }
 
-             if (gstring->lbearing > gstring->width + gstring->sub_lbearing)
-               gstring->lbearing = gstring->width + gstring->sub_lbearing;
-             if (gstring->rbearing < gstring->width + gstring->sub_rbearing)
-               gstring->rbearing = gstring->width + gstring->sub_rbearing;
-             gstring->width += gstring->sub_width;
+             if (gstring->lbearing > gstring->width + extents.lbearing)
+               gstring->lbearing = gstring->width + extents.lbearing;
+             if (gstring->rbearing < gstring->width + extents.rbearing)
+               gstring->rbearing = gstring->width + extents.rbearing;
+             gstring->width += extents.width;
              if (gstring->ascent < rface->ascent)
                gstring->ascent = rface->ascent;
              if (gstring->descent < rface->descent)
@@ -1421,7 +1446,33 @@ alloc_gstring (MFrame *frame, MText *mt, int pos, MDrawControl *control,
 
   if (pos == mt->nchars)
     {
+      MGlyph *g;
+
       gstring = &scratch_gstring;
+      if (gstring->size == 0)
+       {
+         MGlyph g_tmp;
+
+         INIT_GLYPH (g_tmp);
+         g_tmp.type = GLYPH_ANCHOR;
+         APPEND_GLYPH (gstring, g_tmp);
+         APPEND_GLYPH (gstring, g_tmp);
+         APPEND_GLYPH (gstring, g_tmp);
+         gstring->glyphs[1].type = GLYPH_SPACE;
+         gstring->glyphs[1].c = '\n';
+         gstring->glyphs[1].code = '\n';
+       }
+      gstring->from = pos;
+      g = MGLYPH (0);
+      g->rface = frame->rface;
+      g->pos = g->to = pos;
+      g++;
+      g->rface = frame->rface;
+      g->pos = pos++, g->to = pos;
+      g++;
+      g->rface = frame->rface;
+      g->pos = g->to = pos;
+      gstring->to = pos;
     }
   else
     {
@@ -1433,7 +1484,6 @@ alloc_gstring (MFrame *frame, MText *mt, int pos, MDrawControl *control,
   gstring->frame = frame;
   gstring->tick = frame->tick;
   gstring->top = gstring;
-  gstring->mt = mt;
   gstring->control = *control;
   gstring->indent = gstring->width_limit = 0;
   if (control->format)
@@ -1456,9 +1506,9 @@ truncate_gstring (MFrame *frame, MText *mt, MGlyphString *gstring)
   int pos;
 
   /* Setup the array POS_WIDTH so that POS_WIDTH[I - GSTRING->from] is
-     a width of glyphs for the character at I of GSTRING->mt.  If I is
-     not a beginning of a grapheme cluster, the corresponding element
-     is 0.  */
+     a width of glyphs for the character at I of MT.  If I is not a
+     beginning of a grapheme cluster, the corresponding element is
+     0.  */
   MTABLE_ALLOCA (pos_width, gstring->to - gstring->from, MERROR_DRAW);
   memset (pos_width, 0, sizeof (int) * (gstring->to - gstring->from));
   for (g = MGLYPH (1); g->type != GLYPH_ANCHOR; g++)
@@ -1476,11 +1526,15 @@ truncate_gstring (MFrame *frame, MText *mt, MGlyphString *gstring)
   pos = gstring->from + i;
   if (gstring->control.line_break)
     {
-      pos = (*gstring->control.line_break) (gstring->mt, gstring->from + i,
+      pos = (*gstring->control.line_break) (mt, gstring->from + i,
                                            gstring->from, gstring->to, 0, 0);
-      if (pos <= gstring->from || pos >= gstring->to)
-       return;
+      if (pos <= gstring->from)
+       pos = gstring->from + 1;
+      else if (pos >= gstring->to)
+       pos = gstring->to;
     }
+  else if (i == 0)
+    pos++;
   compose_glyph_string (frame, mt, gstring->from, pos, gstring);
   layout_glyph_string (frame, gstring);
 }
@@ -1556,26 +1610,23 @@ get_gstring (MFrame *frame, MText *mt, int pos, int to, MDrawControl *control)
       int beg, end;
       int line = 0, y = 0;
 
-      if (control->two_dimensional)
+      if (pos < mtext_nchars (mt))
        {
          beg = mtext_character (mt, pos, 0, '\n');
          if (beg < 0)
            beg = 0;
          else
            beg++;
-         end = mtext_nchars (mt) + (control->cursor_width != 0);
        }
       else
-       {
-         beg = pos;
-         end = to;
-       }
+       beg = pos;
+      end = mtext_nchars (mt) + (control->cursor_width != 0);
       gstring = alloc_gstring (frame, mt, beg, control, line, y);
-      compose_glyph_string (frame, mt, beg, end, gstring);
+      if (beg < mtext_nchars (mt))
+       compose_glyph_string (frame, mt, beg, end, gstring);
       layout_glyph_string (frame, gstring);
       end = gstring->to;
-      if (control->two_dimensional
-         && gstring->width_limit
+      if (gstring->width_limit
          && gstring->width > gstring->width_limit)
        {
          MGlyphString *gst = gstring;
@@ -1756,7 +1807,6 @@ mdraw__init ()
   memset (&scratch_gstring, 0, sizeof (scratch_gstring));
   MLIST_INIT1 (&scratch_gstring, glyphs, 3);
 
-  Mlatin = msymbol ("latin");
   Minherited = msymbol ("inherited");
 
   McatCc = msymbol ("Cc");
@@ -2288,7 +2338,7 @@ mdraw_text_per_char_extents (MFrame *frame,
       return 0;
     }
 
-  for (g = MGLYPH (1), x = 0; g->type != GLYPH_ANCHOR;)
+  for (g = MGLYPH (1), x = 0; g->type != GLYPH_ANCHOR; g++)
     if (g->pos >= from && g->pos < to)
       {
        int start = g->pos;
@@ -2298,9 +2348,19 @@ mdraw_text_per_char_extents (MFrame *frame,
        int rbearing = g->rbearing;
        int ascent = g->ascent;
        int descent = g->descent;
-       int logical_ascent = g->rface->rfont->ascent;
-       int logical_descent = g->rface->rfont->descent;
+       int logical_ascent;
+       int logical_descent;
 
+       if (g->rface->rfont)
+         {
+           logical_ascent = g->rface->rfont->ascent;
+           logical_descent = g->rface->rfont->descent;
+         }
+       else
+         {
+           logical_ascent = g->rface->ascent;
+           logical_descent = g->rface->descent;
+         }
        for (g++; g->type != GLYPH_ANCHOR && g->pos == start; g++)
          {
            if (lbearing < width + g->lbearing)
@@ -2318,18 +2378,25 @@ mdraw_text_per_char_extents (MFrame *frame,
          end = to;
        while (start < end)
          {
-           ink_array_return[start - from].x = x + lbearing;
-           ink_array_return[start - from].y = - ascent;
-           ink_array_return[start - from].width = rbearing - lbearing;
-           ink_array_return[start - from].height = ascent + descent;
-           logical_array_return[start - from].x = x;
-           logical_array_return[start - from].y = - logical_descent;
-           logical_array_return[start - from].height
-             = logical_ascent + logical_descent;
-           logical_array_return[start - from].width = width;
+           if (ink_array_return)
+             {
+               ink_array_return[start - from].x = x + lbearing;
+               ink_array_return[start - from].y = - ascent;
+               ink_array_return[start - from].width = rbearing - lbearing;
+               ink_array_return[start - from].height = ascent + descent;
+             }
+           if (logical_array_return)
+             {
+               logical_array_return[start - from].x = x;
+               logical_array_return[start - from].y = - logical_descent;
+               logical_array_return[start - from].height
+                 = logical_ascent + logical_descent;
+               logical_array_return[start - from].width = width;
+             }
            start++;
          }
        x += width;
+       g--;
       }
 
   if (overall_ink_return)
@@ -2440,7 +2507,7 @@ mdraw_coordinates_position (MFrame *frame, MText *mt, int from, int to,
   if (! control->orientation_reversed)
     {
       width = gstring->indent;
-      for (g = MGLYPH (1); g[1].type != GLYPH_ANCHOR; g++)
+      for (g = MGLYPH (1); g->type != GLYPH_ANCHOR; g++)
        if (g->pos >= from && g->pos < to)
          {
            width += g->width;
@@ -2459,6 +2526,10 @@ mdraw_coordinates_position (MFrame *frame, MText *mt, int from, int to,
              break;
          }
     }
+  if (g->type == GLYPH_ANCHOR
+      && control->two_dimensional
+      && g[-1].c == '\n')
+    g--;
   from = g->pos;
   M17N_OBJECT_UNREF (gstring->top);