(MSubTextExtents): New type.
[m17n/m17n-lib.git] / src / draw.c
index d182f0c..4f0f887 100644 (file)
 static MSymbol M_glyph_string;
 
 /* Special scripts */
-static MSymbol Mlatin, Minherited;
+static MSymbol Minherited;
 /* Special categories */
 static MSymbol McatCc, McatCf;
 
-static MSymbol Mdepth;
-
 \f
 /* Glyph-string composer.  */
 
@@ -101,62 +99,63 @@ visual_order (MGlyphString *gstring)
 {
   int len = gstring->used - 2;
   MGlyph *glyphs;
-  int *idx = alloca (sizeof (int) * len);
-  int gidx;
   int bidi_sensitive = gstring->control.orientation_reversed;
-  int size = 0;
-  MGlyph *g = MGLYPH (1);
+  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;
-  FriBidiLevel *levels = alloca (sizeof (FriBidiLevel) * len);
+  FriBidiLevel *levels;
 #else  /* not HAVE_FRIBIDI */
   int *logical = alloca (sizeof (int) * len);
   int *indices;
   char *levels = alloca (len);
 #endif /* not HAVE_FRIBIDI */
 
-  while (g->type != GLYPH_ANCHOR)
+  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;
-         levels[size] = 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;
+#endif /* not HAVE_FRIBIDI */
+           }
        }
-      else
-       levels[size] = 0;
-      idx[size] = GLYPH_INDEX (g);
-      logical[size++] = g++->c;
-      while (g->type != GLYPH_ANCHOR && g->combining_code)
-       g++;
+      logical[i] = g->c;
     }
 
   if (! bidi_sensitive)
     return;
 
-  glyphs = alloca (sizeof (MGlyph) * gstring->used);
-  memcpy (glyphs, gstring->glyphs, (sizeof (MGlyph) * gstring->used));
+  glyphs = alloca (sizeof (MGlyph) * len);
+  memcpy (glyphs, gstring->glyphs + 1, sizeof (MGlyph) * len);
 #ifdef HAVE_FRIBIDI
-  visual = alloca (sizeof (FriBidiChar) * size);
-  indices = alloca (sizeof (FriBidiStrIndex) * size);
+  visual = alloca (sizeof (FriBidiChar) * (len + 1));
+  indices = alloca (sizeof (FriBidiStrIndex) * (len + 1));
+  levels = alloca (sizeof (FriBidiLevel) * (len + 1));
 
-  fribidi_log2vis (logical, size, &base, visual, NULL, indices, levels);
+  fribidi_log2vis (logical, len, &base, visual, indices, NULL, levels);
 #else  /* not HAVE_FRIBIDI */
-  indices = alloca (sizeof (int) * size);
-  for (i = 0; i < size; i++)
+  indices = alloca (sizeof (int) * len);
+  for (i = 0; i < len; i++)
     {
       if (levels[i])
        {
          int j, k;
 
-         for (j = i + 1; j < size && levels[j]; j++);
+         for (j = i + 1; j < len && levels[j]; j++);
          for (k = j--; i < k; i++, j--)
            indices[i] = j;
          i--;
@@ -166,36 +165,35 @@ visual_order (MGlyphString *gstring)
     }
 #endif /* not HAVE_FRIBIDI */
 
-  /* IDX are indices to gstring->glyphs[].  The glyphs for LOGICAL[N]
-     starts from gstring->glyphs[IDX[N]].
-
-     INDICES are indices to LOGICAL[].  The glyph for VISUAL[N] is
-     originally at LOGICAL[INDICES[N]].  */
-
-  for (i = 0, gidx = 1; i < size; i++)
+  for (i = 0; i < len;)
     {
+      /* Index into gstring->glyphs plus 1 for GLYPHS[i].  */
       int j = indices[i];
-      int k = idx[j];
+      /* Length of grapheme-cluster */
+      int seglen;
 
-      glyphs[k].bidi_level = levels[j];
+      g = glyphs + i;
 #ifdef HAVE_FRIBIDI
-      if (visual[i] != logical[j])
+      if (visual[j] != logical[i])
        {
          /* Mirrored.  */
-         glyphs[k].c = visual[i];
-         if (glyphs[k].rface->rfont)
-           glyphs[k].code = mfont__encode_char (glyphs[k].rface->rfont,
-                                                glyphs[k].c);
+         g->c = visual[j];
+         if (g->rface->rfont)
+           g->code = mfont__encode_char (g->rface->rfont, g->c);
        }
-#endif /* not HAVE_FRIBIDI */
-      *(MGLYPH (gidx)) = glyphs[k];
-      for (gidx++, k++;
-          k < gstring->used - 1 && glyphs[k].combining_code;
-          gidx++, k++)
+#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++)
        {
-         glyphs[k].bidi_level = levels[j];
-         *(MGLYPH (gidx)) = glyphs[k];
+         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;
     }
 }
 
@@ -238,10 +236,10 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
   MGlyph g_tmp, *g;
   int pos;
   MSymbol language = Mnil, script = Mnil, charset = Mnil;
+  MSymbol non_latin_script = Mnil;
   MRealizedFace *rface = default_rface;
-  int non_ascii_found;
   int size = gstring->control.fixed_width;
-  int i, limit;
+  int i;
   int last;
 
   MLIST_RESET (gstring);
@@ -259,7 +257,6 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
 
   stop = face_change = charset_change = language_change = pos = from;
   last = 0;
-  non_ascii_found = 0;
   while (1)
     {
       int c;
@@ -269,91 +266,113 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
        c = mtext_ref_char (mt, pos);
       else
        c = '\n';
-      g_tmp.category = Mnil;
+      g_tmp.category = mchar_get_prop (c, Mcategory);
       if (c < 0x100)
        {
-         if (c == ' ' || c == '\n' || c == '\t')
-           g_tmp.type = GLYPH_SPACE, this_script = Mnil;
-         else
-           g_tmp.type = GLYPH_CHAR, this_script = Mlatin;
+         /* Short cut for the obvious case.  */
+         g_tmp.type = (c == ' ' || c == '\n' || c == '\t'
+                       ? GLYPH_SPACE : GLYPH_CHAR);
+         this_script = Mlatin;
        }
       else
        {
-         g_tmp.category = mchar_get_prop (c, Mcategory);
          g_tmp.type = GLYPH_CHAR;
          this_script = (MSymbol) mchar_get_prop (c, Mscript);
-         if (this_script == Minherited)
+         if (this_script == Minherited || this_script == Mnil)
            this_script = script;
+         if (this_script == Mnil)
+           this_script = non_latin_script;
+         if (this_script == Mnil)
+           {
+             /* Search forward for a character that explicitly
+                specifies a non-latin script.  */
+             int c1;
+             MSymbol sym;
+
+             for (i = pos + 1; i < to; i++)
+               if ((c1 = mtext_ref_char (mt, i)) >= 0x100
+                   && (sym = mchar_get_prop (c1, Mscript)) != Mnil
+                   && sym != Minherited)
+                 {
+                   this_script = sym;
+                   break;
+                 }
+           }
        }
 
       if (pos == stop || script != this_script
          || MGLYPH (last)->type != g_tmp.type)
        {
          g = MGLYPH (last);
-         if (non_ascii_found && g->type == GLYPH_CHAR)
+         if (g->type != GLYPH_ANCHOR)
            while (g < gstring->glyphs + gstring->used)
              g = mface__for_chars (script, language, charset,
                                    g, gstring->glyphs + gstring->used, size);
-         last = gstring->used;
-         non_ascii_found = 0;
-         script = this_script;
          if (pos == to)
            break;
-         if (pos < mtext_nchars (mt) && pos == language_change)
-           {
-             language = (MSymbol) mtext_get_prop (mt, pos, Mlanguage);
-             mtext_prop_range (mt, Mlanguage, pos, NULL, &language_change, 0);
-           }
-         if (pos < mtext_nchars (mt) && pos == charset_change)
-           {
-             charset = (MSymbol) mtext_get_prop (mt, pos, Mcharset);
-             mtext_prop_range (mt, Mcharset, pos, NULL, &charset_change, 0);
-           }
-         if (pos < mtext_nchars (mt) && pos == face_change)
+         last = gstring->used;
+         script = this_script;
+         if (script != Mnil && script != Mlatin)
+           non_latin_script = script;
+         if (pos == stop)
            {
-             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);
+             if (pos < mtext_nchars (mt) && pos == language_change)
+               {
+                 language = (MSymbol) mtext_get_prop (mt, pos, Mlanguage);
+                 mtext_prop_range (mt, Mlanguage, pos, NULL,
+                                   &language_change, 0);
+               }
+             if (pos < mtext_nchars (mt) && pos == charset_change)
+               {
+                 charset = (MSymbol) mtext_get_prop (mt, pos, Mcharset);
+                 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;             
            }
-         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 = g_tmp.code = c;
+      g_tmp.c = c;
       g_tmp.pos = pos++;
       g_tmp.to = pos;
       g_tmp.rface = rface;
       
-      if (c >= 0x100)
-       non_ascii_found = 1;
-      else if (g_tmp.type == GLYPH_CHAR && (c <= 32 || c == 127))
+      if ((c <= 32 || c == 127) && g_tmp.type == GLYPH_CHAR)
        {
-         g_tmp.code = '^';
-         APPEND_GLYPH (gstring, g_tmp);
-         if (c < ' ')
-           g_tmp.code = g_tmp.c + 0x40;
-         else
-           g_tmp.code = '?';
+         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]);
        }
-      APPEND_GLYPH (gstring, g_tmp);
+      else
+       APPEND_GLYPH (gstring, g_tmp);
       if (c == '\n'
          && gstring->control.two_dimensional)
        break;
     }
 
-  limit = pos - from;
-
   /* Append an anchor glyph.  */
   g_tmp.type = GLYPH_ANCHOR;
   g_tmp.c = 0;
@@ -418,6 +437,8 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
                }
              if (start + 1 < i)
                reorder_combining_chars (gstring, start, i);
+             if (this->type == GLYPH_ANCHOR)
+               break;
            }
          g = MGLYPH (i);
        }
@@ -482,20 +503,37 @@ 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;)
+    {
+      if ( MGLYPH (i)->otf_encoded)
+       i++;
+      else
+       {
+         int j = i++;
 
-  mfont__get_metric (gstring, from, to);
+         while (i < to && ! MGLYPH (i)->otf_encoded) i++;
+         mfont__get_metric (gstring, j, i);
+       }
+    }
 
+  g = MGLYPH (from);
   while (g < last_g)
     {
       MGlyph *base = g++;
@@ -506,6 +544,21 @@ layout_glyphs (MFrame *frame, MGlyphString *gstring, int from, int to)
       if (g == last_g || ! g->combining_code)
        {
          /* No combining.  */
+         if (base->width == 0 && ! base->left_padding && ! base->right_padding
+             && GLYPH_INDEX (base) > from)
+           {
+             MGlyph *prev = base - 1; 
+
+             if (base->pos < prev->pos)
+               prev->pos = base->pos;
+             else
+               base->pos = prev->pos;
+             if (base->to > prev->to)
+               prev->to = base->to;
+             else
+               base->to = prev->to;
+           }
+
          if (base->left_padding && base->lbearing < 0)
            {
              base->xoff = - base->lbearing;
@@ -517,8 +570,9 @@ layout_glyphs (MFrame *frame, MGlyphString *gstring, int from, int to)
            {
              base->width = base->rbearing;
            }
-         lbearing = (base->lbearing < 0 ? base->lbearing : 0);
-         rbearing = base->rbearing;
+         lbearing = (base->xoff + base->lbearing < 0
+                     ? base->xoff + base->lbearing : 0);
+         rbearing = base->xoff + base->rbearing;
        }
       else
        {
@@ -538,48 +592,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)
@@ -619,16 +678,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;
 }
 
 
@@ -735,12 +791,17 @@ layout_glyph_string (MFrame *frame, MGlyphString *gstring)
            {
              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->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;
@@ -748,11 +809,12 @@ layout_glyph_string (MFrame *frame, MGlyphString *gstring)
                  pad.xoff = 0;
                  pad.lbearing = 0;
                  pad.width = pad.rbearing = extra_width;
+                 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)
@@ -771,7 +833,7 @@ layout_glyph_string (MFrame *frame, MGlyphString *gstring)
                        }
                      else
                        {
-                         extra_width -= g->width - 2;
+                         extra_width = g->width - 2;
                          g->width = 2;
                        }
                      gstring->width -= extra_width;
@@ -779,36 +841,38 @@ layout_glyph_string (MFrame *frame, MGlyphString *gstring)
                    }
                }
 
-             extra_width = gstring->sub_rbearing - gstring->sub_width;
-             if (extra_width > 0)
+             g = MGLYPH (to);
+             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)))
                {
-                 g = MGLYPH (to);
                  if (g->type == GLYPH_SPACE && box == g->rface->box)
                    {
-                     g--;
-                     pad = *g;
+                     pad = g[-1];
                      pad.type = GLYPH_PAD;
                      pad.xoff = 0;
                      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)
                gstring->descent = rface->descent;
-             g = MGLYPH (to);
            }
          else
            {
@@ -981,7 +1045,8 @@ draw_background (MFrame *frame, MDrawWindow win, int x, int y,
       if (gstring->from <= control->cursor_pos
          && gstring->to > control->cursor_pos)
        cursor_pos = control->cursor_pos;
-      if (cursor_bidi
+      if (cursor_pos >= 0
+         && cursor_bidi
          && gstring->from <= control->cursor_pos - 1
          && gstring->to > control->cursor_pos - 1)
        prev_pos = control->cursor_pos - 1;
@@ -1023,10 +1088,11 @@ draw_background (MFrame *frame, MDrawWindow win, int x, int y,
                this_x += fromg->width, this_width -= fromg->width;
              if (g[-1].type == GLYPH_BOX)
                this_width -= g[-1].width;
-             mwin__fill_space (frame, win, rface, 0,
-                               this_x, y - gstring->text_ascent, this_width,
-                               gstring->text_ascent + gstring->text_descent,
-                               control->clip_region);
+             (frame->driver->fill_space)
+               (frame, win, rface, 0,
+                this_x, y - gstring->text_ascent, this_width,
+                gstring->text_ascent + gstring->text_descent,
+                control->clip_region);
            }
          if (cursor)
            {
@@ -1042,30 +1108,27 @@ draw_background (MFrame *frame, MDrawWindow win, int x, int y,
                                ? control->cursor_width : cursor_width);
                }
              else
-               {
-                 if (cursor->bidi_level % 2)
-                   rect.x += cursor_width - 1;
-                 rect.width = 1;
-               }
-             mwin__fill_space (frame, win, rface, 1,
-                               rect.x, rect.y, rect.width, rect.height,
-                               control->clip_region);
+               rect.width = 1;
+             if (cursor->bidi_level % 2)
+               rect.x += cursor_width - rect.width;
+             (*frame->driver->fill_space)
+               (frame, win, rface, 1, rect.x, rect.y, rect.width, rect.height,
+                control->clip_region);
              if (! region)
-               region = mwin__region_from_rect (&rect);
+               region = (*frame->driver->region_from_rect) (&rect);
              else
-               mwin__region_add_rect (region, &rect);
-             mwin__verify_region (frame, region);
+               (*frame->driver->region_add_rect) (region, &rect);
              if (cursor_bidi)
                {
                  if (cursor->bidi_level % 2)
                    rect.x -= 3;
                  rect.height = 2;
                  rect.width = cursor_width < 4 ? cursor_width : 4;
-                 mwin__fill_space (frame, win, rface, 1,
-                                   rect.x, rect.y, rect.width, rect.height,
-                                   control->clip_region);
-                 mwin__region_add_rect (region, &rect);
-                 mwin__verify_region (frame, region);
+                 (*frame->driver->fill_space)
+                   (frame, win, rface, 1,
+                    rect.x, rect.y, rect.width, rect.height,
+                    control->clip_region);
+                 (*frame->driver->region_add_rect) (region, &rect);
                }
            }
 
@@ -1096,24 +1159,23 @@ draw_background (MFrame *frame, MDrawWindow win, int x, int y,
                  rect.y = y - gstring->text_ascent;
                  rect.height = gstring->text_ascent + gstring->text_descent;
                  rect.width = 1;
-                 mwin__fill_space (frame, win, rface, 1,
-                                   rect.x, rect.y, rect.width, rect.height,
-                                   control->clip_region);
+                 (*frame->driver->fill_space)
+                   (frame, win, rface, 1,
+                    rect.x, rect.y, rect.width, rect.height,
+                    control->clip_region);
                  if (! region)
-                   region = mwin__region_from_rect (&rect);
+                   region = (*frame->driver->region_from_rect) (&rect);
                  else
-                   mwin__region_add_rect (region, &rect);
-                 mwin__verify_region (frame, region);
+                   (*frame->driver->region_add_rect) (region, &rect);
                  rect.y += rect.height - 2;
                  rect.height = 2;
                  rect.width = cursor_width < 4 ? cursor_width : 4;
                  if (! (cursor->bidi_level % 2))
                    rect.x -= rect.width - 1;
-                 mwin__fill_space (frame, win, rface, 1,
+                 (*frame->driver->fill_space) (frame, win, rface, 1,
                                    rect.x, rect.y, rect.width, rect.height,
                                    control->clip_region);
-                 mwin__region_add_rect (region, &rect);
-                 mwin__verify_region (frame, region);
+                 (*frame->driver->region_add_rect) (region, &rect);
                }
            }
          x += width;
@@ -1137,7 +1199,7 @@ render_glyphs (MFrame *frame, MDrawWindow win, int x, int y, int width,
     {
       MDrawMetric rect;
 
-      mwin__region_to_rect (region, &rect);
+      (*frame->driver->region_to_rect) (region, &rect);
       if (rect.x > x)
        {
          while (g != gend && x + g->rbearing <= rect.x)
@@ -1175,17 +1237,18 @@ render_glyphs (MFrame *frame, MDrawWindow win, int x, int y, int width,
          while (g != gend
                 && g->type == from_g->type
                 && g->rface == rface
-                && (g->code < 0) == (from_g->code < 0)
+                && ((g->code == MCHAR_INVALID_CODE)
+                    == (from_g->code == MCHAR_INVALID_CODE))
                 && g->enabled)
            width += g++->width;
 
          if (from_g->type == GLYPH_CHAR)
            {
-             if (rface->rfont && from_g->code >= 0)
+             if (rface->rfont && from_g->code != MCHAR_INVALID_CODE)
                (rface->rfont->driver->render) (win, x, y, gstring, from_g, g,
                                                reverse, region);
              else
-               mwin__draw_empty_boxes (win, x, y, gstring, from_g, g,
+               (*frame->driver->draw_empty_boxes) (win, x, y, gstring, from_g, g,
                                        reverse, region);
            }
          else if (from_g->type == GLYPH_BOX)
@@ -1193,18 +1256,18 @@ render_glyphs (MFrame *frame, MDrawWindow win, int x, int y, int width,
              /* Draw the left or right side of a box.  If
                 from_g->lbearing is nonzero, this is the left side,
                 else this is the right side.  */
-             mwin__draw_box (frame, win, gstring, from_g, x, y, 0, region);
+             (*frame->driver->draw_box) (frame, win, gstring, from_g, x, y, 0, region);
            }
 
          if (from_g->type != GLYPH_BOX)
            {
              if (rface->hline)
-               mwin__draw_hline (frame, win, gstring, rface, reverse,
+               (*frame->driver->draw_hline) (frame, win, gstring, rface, reverse,
                                  x, y, width, region);
              if (rface->box
                  && ! reverse)
                /* Draw the top and bottom side of a box.  */
-                  mwin__draw_box (frame, win, gstring, from_g,
+               (*frame->driver->draw_box) (frame, win, gstring, from_g,
                                   x, y, width, region);
            }
          x += width;
@@ -1321,9 +1384,9 @@ render_glyph_string (MFrame *frame, MDrawWindow win, int x, int y,
        {
          rect.y = y - gstring->line_ascent;
          rect.height = gstring->height;
-         clip_region = mwin__region_from_rect (&rect);
+         clip_region = (*frame->driver->region_from_rect) (&rect);
          if (control->clip_region)
-           mwin__intersect_region (clip_region, control->clip_region);
+           (*frame->driver->intersect_region) (clip_region, control->clip_region);
        }
       else
        clip_region = control->clip_region;
@@ -1336,14 +1399,14 @@ render_glyph_string (MFrame *frame, MDrawWindow win, int x, int y,
   if (cursor_region)
     {
       if (clip_region)
-       mwin__intersect_region (cursor_region, clip_region);
+       (*frame->driver->intersect_region) (cursor_region, clip_region);
       render_glyphs (frame, win, x, y, to_x - x, gstring, from_idx, to_idx,
                     1, cursor_region);
     }
   if (clip_region != control->clip_region)
-    mwin__free_region (clip_region);
+    (*frame->driver->free_region) (clip_region);
   if (cursor_region)
-    mwin__free_region (cursor_region);
+    (*frame->driver->free_region) (cursor_region);
   return;
 }
 
@@ -1385,7 +1448,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)
@@ -1393,9 +1455,6 @@ alloc_gstring (MFrame *frame, MText *mt, int pos, MDrawControl *control,
   else
     gstring->width_limit = control->max_line_width;
   gstring->anti_alias = control->anti_alias;
-  if (gstring->anti_alias
-      && (unsigned) mwin__device_get_prop (frame->device, Mdepth) < 8)
-    gstring->anti_alias = 0;
   return gstring;
 }
 
@@ -1411,9 +1470,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++)
@@ -1431,11 +1490,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);
 }
@@ -1468,7 +1531,9 @@ get_gstring (MFrame *frame, MText *mt, int pos, int to, MDrawControl *control)
              || gstring->tick != frame->tick
              || memcmp (control, &gstring->control,
                         (char *) (&control->with_cursor)
-                        - (char *) (control)))
+                        - (char *) (control))
+             || control->cursor_width != gstring->control.cursor_width
+             || control->cursor_bidi != gstring->control.cursor_bidi)
            {
              mtext_detach_property (prop);
              gstring = NULL;
@@ -1509,26 +1574,18 @@ get_gstring (MFrame *frame, MText *mt, int pos, int to, MDrawControl *control)
       int beg, end;
       int line = 0, y = 0;
 
-      if (control->two_dimensional)
-       {
-         beg = mtext_character (mt, pos, 0, '\n');
-         if (beg < 0)
-           beg = 0;
-         else
-           beg++;
-         end = mtext_nchars (mt) + (control->cursor_width != 0);
-       }
+      beg = mtext_character (mt, pos, 0, '\n');
+      if (beg < 0)
+       beg = 0;
       else
-       {
-         beg = pos;
-         end = to;
-       }
+       beg++;
+      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);
       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;
@@ -1709,12 +1766,10 @@ mdraw__init ()
   memset (&scratch_gstring, 0, sizeof (scratch_gstring));
   MLIST_INIT1 (&scratch_gstring, glyphs, 3);
 
-  Mlatin = msymbol ("latin");
   Minherited = msymbol ("inherited");
 
   McatCc = msymbol ("Cc");
   McatCf = msymbol ("Cf");
-  Mdepth = msymbol ("depth");
 
   MbidiR = msymbol ("R");
   MbidiAL = msymbol ("AL");
@@ -1895,6 +1950,7 @@ mdraw_text (MFrame *frame, MDrawWindow win, int x, int y,
 {
   MDrawControl control;
 
+  M_CHECK_WRITABLE (frame, MERROR_DRAW, -1);
   memset (&control, 0, sizeof control);
   control.as_image = 0;
   return draw_text (frame, win, x, y, mt, from, to, &control);
@@ -1957,6 +2013,7 @@ mdraw_image_text (MFrame *frame, MDrawWindow win, int x, int y,
 {
   MDrawControl control;
 
+  M_CHECK_WRITABLE (frame, MERROR_DRAW, -1);
   memset (&control, 0, sizeof control);
   control.as_image = 1;
   return draw_text (frame, win, x, y, mt, from, to, &control);
@@ -2000,6 +2057,7 @@ int
 mdraw_text_with_control (MFrame *frame, MDrawWindow win, int x, int y,
                         MText *mt, int from, int to, MDrawControl *control)
 {
+  M_CHECK_WRITABLE (frame, MERROR_DRAW, -1);
   return draw_text (frame, win, x, y, mt, from, to, control);
 }
 
@@ -2225,7 +2283,7 @@ mdraw_text_per_char_extents (MFrame *frame,
   ASSURE_CONTROL (control);
   *num_chars_return = to - from;
   if (array_size < *num_chars_return)
-    return 0;
+    MERROR (MERROR_DRAW, -1);
   if (overall_logical_return)
     memset (overall_logical_return, 0, sizeof (MDrawMetric));
   if (overall_ink_return)
@@ -2239,7 +2297,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;
@@ -2249,9 +2307,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)
@@ -2269,18 +2337,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)
@@ -2299,7 +2374,7 @@ mdraw_text_per_char_extents (MFrame *frame,
     }
 
   M17N_OBJECT_UNREF (gstring->top);
-  return 1;
+  return 0;
 }
 
 /*=*/
@@ -2391,7 +2466,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;
@@ -2486,14 +2561,15 @@ mdraw_glyph_info (MFrame *frame, MText *mt, int from, int pos,
     }
   info->from = g->pos;
   info->to = g->to;
-  info->this.x = g->lbearing;
-  info->this.y = - gstring->line_ascent;
-  info->this.height = gstring->height;
+  info->metrics.x = g->lbearing;
+  info->metrics.y = - gstring->line_ascent;
+  info->metrics.height = gstring->height;
+  info->metrics.width = - g->lbearing + g->width;
   if (g->rface->rfont)
     info->font = &g->rface->rfont->font;
   else
     info->font = NULL;
-  /* info->this.width is calculated later.  */
+  /* info->logical_width is calculated later.  */
 
   if (info->from > info->line_from)
     {
@@ -2570,9 +2646,10 @@ mdraw_glyph_info (MFrame *frame, MText *mt, int from, int pos,
   else
     info->next_to = -1;
 
-  for (info->this.width = (g++)->width;
+  for (info->logical_width = (g++)->width;
        g->pos == pos && g->type != GLYPH_ANCHOR;
-       info->this.width += (g++)->width);
+       info->metrics.width += g->width, info->logical_width += (g++)->width);
+  info->metrics.width += g[-1].rbearing - g[-1].width;
 
   if (g->type != GLYPH_ANCHOR)
     info->right_from = g->pos, info->right_to = g->to;
@@ -2610,6 +2687,110 @@ mdraw_glyph_info (MFrame *frame, MText *mt, int from, int pos,
 /*=*/
 
 /***en
+    @brief Compute information about glyph sequence.
+
+    The mdraw_glyph_list () function computes information about glyphs
+    corresponding to the text between $FROM and $TO of M-text $MT when
+    it is drawn on a window of frame $FRAME using the
+    mdraw_text_with_control () function with the drawing control
+    object $CONTROL.  $GLYPHS is an array of objects to store the
+    information, and $ARRAY_SIZE is the array size.
+
+    If $ARRAY_SIZE is large enough to cover all glyphs, it stores the
+    number of actually filled elements in the place pointed by
+    $NUM_GLYPHS_RETURN, and returns 0.
+
+    Otherwise, it stores the required array size in the place pointed
+    by $NUM_GLYPHS_RETURN, and returns -1.  */
+
+/***ja
+    @brief ¥°¥ê¥ÕÎó¤Ë´Ø¤¹¤ë¾ðÊó¤ò·×»»¤¹¤ë.
+
+    ´Ø¿ô mdraw_glyph_list () ¤Ï¡¢´Ø¿ô mdraw_text_with_control () ¤¬ÉÁ²è
+    À©¸æ¥ª¥Ö¥¸¥§¥¯¥È $CONTROL ¤òÍѤ¤¤ÆM-text $MT ¤Î $FROM ¤«¤é $TO ¤Þ¤Ç
+    ¤ò¥Õ¥ì¡¼¥à $FRAME ¤ËÉÁ²è¤·¤¿¾ì¹ç¤Î¡¢³Æ¥°¥ê¥Õ¤Î¾ðÊó¤ò $GLYPHS ¤¬»Ø¤¹
+    ÇÛÎó¤Ë³ÊǼ¤¹¤ë¡£ $ARRAY_SIZE ¤Ï¤½¤ÎÇÛÎó¤Î¥µ¥¤¥º¤Ç¤¢¤ë¡£
+
+    ¤â¤· $ARRAY_SIZE ¤¬¤¹¤Ù¤Æ¤Î¥°¥ê¥Õ¤Ë¤Ä¤¤¤Æ¤Î¾ðÊó¤ò³ÊǼ¤¹¤ë¤Î¤Ë½½Ê¬¤Ç
+    ¤¢¤ì¤Ð¡¢ $NUM_GLYPHS_RETURN ¤¬»Ø¤¹¾ì½ê¤Ë¼ÂºÝ¤ËËä¤á¤¿Í×ÁǤοô¤òÀßÄê
+    ¤· 0 ¤òÊÖ¤¹¡£  */
+
+/***
+    @seealso
+    MDrawGlyph
+*/
+
+int
+mdraw_glyph_list (MFrame *frame, MText *mt, int from, int to,
+                 MDrawControl *control, MDrawGlyph *glyphs,
+                 int array_size, int *num_glyphs_return)
+{
+  MGlyphString *gstring;
+  MGlyph *g;
+  int n;
+  int pad_width = 0;
+
+  ASSURE_CONTROL (control);
+  *num_glyphs_return = 0;
+  M_CHECK_RANGE (mt, from, to, -1, 0);
+  gstring = get_gstring (frame, mt, from, to, control);
+  if (! gstring)
+    return -1;
+  for (g = MGLYPH (1), n = 0; g->type != GLYPH_ANCHOR; g++)
+    {
+      if (g->type == GLYPH_BOX
+         || g->pos < from || g->pos >= to)
+       continue;
+      if (g->type == GLYPH_PAD)
+       {
+         if (g->left_padding)
+           pad_width = g->width;
+         else if (n > 0)
+           {
+             pad_width = 0;
+             glyphs[-1].x_advance += g->width;
+           }
+         continue;
+       }
+      if (n < array_size)
+       {
+         glyphs->from = g->pos;
+         glyphs->to = g->to;
+         glyphs->glyph_code = g->code;
+         glyphs->x_off = g->xoff + pad_width;
+         glyphs->y_off = g->yoff;
+         glyphs->lbearing = g->lbearing;
+         glyphs->rbearing = g->rbearing;
+         glyphs->ascent = g->ascent;
+         glyphs->descent = g->descent;
+         glyphs->x_advance = g->width + pad_width;
+         glyphs->y_advance = 0;
+         if (g->rface->rfont)
+           {
+             glyphs->font = &g->rface->rfont->font;
+             glyphs->font_type = g->rface->rfont->type;
+             glyphs->fontp = g->rface->rfont->fontp;
+           }
+         else
+           {
+             glyphs->font = NULL;
+             glyphs->font_type = Mnil;
+             glyphs->fontp = NULL;
+           }
+         pad_width = 0;
+         glyphs++;
+       }
+      n++;
+    }
+  M17N_OBJECT_UNREF (gstring->top);
+
+  *num_glyphs_return = n;
+  return (n <= array_size ? 0 : -1);
+}
+
+/*=*/
+
+/***en
     @brief Draw one or more textitems.
 
     The mdraw_text_items () function draws one or more M-texts on
@@ -2635,6 +2816,8 @@ void
 mdraw_text_items (MFrame *frame, MDrawWindow win, int x, int y,
                  MDrawTextItem *items, int nitems)
 {
+  if (! (frame->device_type & MDEVICE_SUPPORT_OUTPUT))
+    return;
   while (nitems-- > 0)
     {
       if (items->face)
@@ -2734,18 +2917,18 @@ mdraw_default_line_break (MText *mt, int pos,
 
     If pointer $OVERALL_RETURN is not @c NULL, this function also
     computes the extents of the overall text and stores the results in
-    the members of the structure pointed to by $OVERALL_RETURN  */
+    the members of the structure pointed to by $OVERALL_RETURN.  */
 
 /***ja
     @brief M-text ¤Îʸ»úËè¤Îɽ¼¨ÈϰϾðÊó¤òÆÀ¤ë.
 
     ´Ø¿ô mdraw_per_char_extents () ¤Ï¡¢M-text $MT Ãæ¤Î³Æʸ»ú¤Îɽ¼¨ÈÏ°Ï
     ¤ò·×»»¤¹¤ë¡£¤³¤Î·×»»¤ËÍѤ¤¤ë¥Õ¥©¥ó¥È¤Ï¡¢$MT ¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ç
-    »ØÄꤵ¤ì¤¿¥Õ¥§¡¼¥¹¤È¡¢¥Õ¥ì¡¼¥à $FRAME ¤Î¥Ç¥Õ¥©¥ë¥È¥Õ¥§¡¼¥¹¤Ë¤è¤Ã¤Æ·è
-    ¤Þ¤ë¡£$ARRAY_RETURN ¤Î³ÆÍ×ÁǤϡ¢Åö³º M-text Ãæ¤Î³Æʸ»ú¤Îɽ¼¨ÈÏ°Ï
-    ¾ðÊó¤Ë¤è¤Ã¤Æ½ç¤ËËä¤á¤é¤ì¤ë¡£¤³¤Îɽ¼¨ÈϰϾðÊó¤Ï¡¢M-text ¤Îɽ¼¨¸¶ÅÀ
-    ¤«¤é¤ÎÁêÂаÌÃ֤Ǥ¢¤ë¡£$ARRAY_RETURN ¤ÎÍ×ÁÇ¿ô¤Ï¡¢M-text ¤Îʸ»ú¿ô°Ê
-    ¾å¤Ç¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£
+    »ØÄꤵ¤ì¤¿¥Õ¥§¡¼¥¹¤Èa¡¢¥Õ¥ì¡¼¥à $FRAME ¤Î¥Ç¥Õ¥©¥ë¥È¥Õ¥§¡¼¥¹¤Ë¤è¤Ã¤Æ
+    ·è¤Þ¤ë¡£$ARRAY_RETURN ¤Î³ÆÍ×ÁǤϡ¢Åö³º M-text Ãæ¤Î³Æʸ»ú¤Îɽ¼¨ÈÏ°Ï
+    ¾ðÊó¤Ë¤è¤Ã¤Æ½ç¤ËËä¤á¤é¤ì¤ë¡£¤³¤Îɽ¼¨ÈϰϾðÊó¤Ï¡¢M-text ¤Îɽ¼¨¸¶ÅÀ¤«
+    ¤é¤ÎÁêÂаÌÃ֤Ǥ¢¤ë¡£$ARRAY_RETURN ¤ÎÍ×ÁÇ¿ô¤Ï¡¢M-text ¤Î°Ê¾å¤Ç¤Ê¤±¤ì
+    ¤Ð¤Ê¤é¤Ê¤¤¡£
 
     ¥Ý¥¤¥ó¥¿ $OVERALL_RETURN ¤¬ @c NULL ¤Ç¤Ê¤¤¾ì¹ç¤Ï¡¢¥Æ¥­¥¹¥ÈÁ´ÂΤÎɽ
     ¼¨ÈϰϾðÊó¤â·×»»¤·¡¢¤½¤Î·ë²Ì¤ò $OVERALL_RETURN ¤Î»Ø¤¹¹½Â¤ÂΤ˳ÊǼ
@@ -2755,9 +2938,13 @@ mdraw_default_line_break (MText *mt, int pos,
 
 void
 mdraw_per_char_extents (MFrame *frame, MText *mt,
-  MDrawMetric *array_return,
-  MDrawMetric *overall_return)
+                       MDrawMetric *array_return,
+                       MDrawMetric *overall_return)
 {
+  int n = mtext_nchars (mt);
+
+  mdraw_text_per_char_extents (frame, mt, 0, n, NULL, array_return, NULL,
+                              n, &n, overall_return, NULL);
 }
 
 /***en