Update copyright years
[m17n/m17n-lib.git] / src / face.c
index db7c807..402c366 100644 (file)
@@ -1,5 +1,5 @@
 /* face.c -- face module.
 /* face.c -- face module.
-   Copyright (C) 2003, 2004
+   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
      National Institute of Advanced Industrial Science and Technology (AIST)
      Registration Number H15PRO112
 
      National Institute of Advanced Industrial Science and Technology (AIST)
      Registration Number H15PRO112
 
@@ -17,7 +17,7 @@
 
    You should have received a copy of the GNU Lesser General Public
    License along with the m17n library; if not, write to the Free
 
    You should have received a copy of the GNU Lesser General Public
    License along with the m17n library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    02111-1307, USA.  */
 
 /***en
    02111-1307, USA.  */
 
 /***en
@@ -33,8 +33,8 @@
     #Mfoundry, #Mfamily, #Mweight, #Mstyle, #Mstretch, #Madstyle,
     #Msize, #Mfontset, #Mratio, #Mhook_func, #Mhook_arg
 
     #Mfoundry, #Mfamily, #Mweight, #Mstyle, #Mstretch, #Madstyle,
     #Msize, #Mfontset, #Mratio, #Mhook_func, #Mhook_arg
 
-    "The face property that belongs to face F and whose key is @c xxx"
-    may be shortened to "the xxx property of F".
+    The notation "xxx property of F" means the face property that
+    belongs to face F and whose key is @c Mxxx.
 
     The M-text drawing functions first search an M-text for the text
     property whose key is the symbol #Mface, then draw the M-text
 
     The M-text drawing functions first search an M-text for the text
     property whose key is the symbol #Mface, then draw the M-text
@@ -243,7 +243,7 @@ serialize_face (void *val)
     MSymbol *key;
     MSymbol *type;
     MPlist *(*func) (MPlist *plist, void *val);
     MSymbol *key;
     MSymbol *type;
     MPlist *(*func) (MPlist *plist, void *val);
-  } serializer[MFACE_PROPERTY_MAX]
+  } serializer[MFACE_RATIO + 1]
       = { { &Mfoundry,         &Msymbol },
          { &Mfamily,           &Msymbol },
          { &Mweight,           &Msymbol },
       = { { &Mfoundry,         &Msymbol },
          { &Mfamily,           &Msymbol },
          { &Mweight,           &Msymbol },
@@ -257,11 +257,9 @@ serialize_face (void *val)
          { &Mhline,            NULL },
          { &Mbox,              NULL },
          { &Mvideomode,        &Msymbol },
          { &Mhline,            NULL },
          { &Mbox,              NULL },
          { &Mvideomode,        &Msymbol },
-         { NULL,               NULL}, /* MFACE_HOOK_FUNC */
-         { NULL,               NULL}, /* MFACE_HOOK_ARG */
          { &Mratio,            &Minteger } };
   
          { &Mratio,            &Minteger } };
   
-  for (i = 0; i < MFACE_PROPERTY_MAX; i++)
+  for (i = 0; i <= MFACE_RATIO; i++)
     if (face->property[i] && serializer[i].key)
       {
        pl = mplist_add (pl, Msymbol, *serializer[i].key);
     if (face->property[i] && serializer[i].key)
       {
        pl = mplist_add (pl, Msymbol, *serializer[i].key);
@@ -363,7 +361,7 @@ deserialize_face (MPlist *plist)
       plist = MPLIST_NEXT (plist);
       if (MPLIST_TAIL_P (plist))
        break;
       plist = MPLIST_NEXT (plist);
       if (MPLIST_TAIL_P (plist))
        break;
-      if (index < 0 || index >= MFACE_PROPERTY_MAX)
+      if (index < 0 || index > MFACE_RATIO)
        continue;
       if (key == Mfoundry || key == Mfamily || key == Mweight || key == Mstyle
          || key == Mstretch || key == Madstyle
        continue;
       if (key == Mfoundry || key == Mfamily || key == Mweight || key == Mstyle
          || key == Mstretch || key == Madstyle
@@ -419,8 +417,10 @@ mface__init ()
 
   M17N_OBJECT_ADD_ARRAY (face_table, "Face");
   Mface = msymbol_as_managing_key ("face");
 
   M17N_OBJECT_ADD_ARRAY (face_table, "Face");
   Mface = msymbol_as_managing_key ("face");
-  msymbol_put (Mface, Mtext_prop_serializer, (void *) serialize_face);
-  msymbol_put (Mface, Mtext_prop_deserializer, (void *) deserialize_face);
+  msymbol_put_func (Mface, Mtext_prop_serializer,
+                   M17N_FUNC (serialize_face));
+  msymbol_put_func (Mface, Mtext_prop_deserializer,
+                   M17N_FUNC (deserialize_face));
 
   Mforeground = msymbol ("foreground");
   Mbackground = msymbol ("background");
 
   Mforeground = msymbol ("foreground");
   Mbackground = msymbol ("background");
@@ -442,7 +442,7 @@ mface__init ()
       MSymbol *key;
       /* Index (enum face_property) of the face property. */
       int index;
       MSymbol *key;
       /* Index (enum face_property) of the face property. */
       int index;
-    } mface_prop_data[MFACE_PROPERTY_MAX] =
+    } mface_prop_data[MFACE_HOOK_ARG + 1] =
        { { &Mfoundry,          MFACE_FOUNDRY },
          { &Mfamily,           MFACE_FAMILY },
          { &Mweight,           MFACE_WEIGHT },
        { { &Mfoundry,          MFACE_FOUNDRY },
          { &Mfamily,           MFACE_FAMILY },
          { &Mweight,           MFACE_WEIGHT },
@@ -456,10 +456,8 @@ mface__init ()
          { &Mhline,            MFACE_HLINE },
          { &Mbox,              MFACE_BOX },
          { &Mvideomode,        MFACE_VIDEOMODE },
          { &Mhline,            MFACE_HLINE },
          { &Mbox,              MFACE_BOX },
          { &Mvideomode,        MFACE_VIDEOMODE },
-         { &Mhook_func,        MFACE_HOOK_FUNC },
-         { &Mhook_arg,         MFACE_HOOK_ARG },
          { &Mratio,            MFACE_RATIO },
          { &Mratio,            MFACE_RATIO },
-       };
+         { &Mhook_arg,         MFACE_HOOK_ARG } };
 
     for (i = 0; i < MFACE_PROPERTY_MAX; i++)
       /* We add one to distinguish it from no-property.  */
 
     for (i = 0; i < MFACE_PROPERTY_MAX; i++)
       /* We add one to distinguish it from no-property.  */
@@ -488,7 +486,7 @@ mface__init ()
   mface__default->property[MFACE_HLINE] = hline;
   mface__default->property[MFACE_BOX] = box;
   mface__default->property[MFACE_VIDEOMODE] = Mnormal;
   mface__default->property[MFACE_HLINE] = hline;
   mface__default->property[MFACE_BOX] = box;
   mface__default->property[MFACE_VIDEOMODE] = Mnormal;
-  mface__default->property[MFACE_HOOK_FUNC] = (void *) noop_hook;
+  mface__default->hook = noop_hook;
 
   mface_normal_video = mface ();
   mface_normal_video->property[MFACE_VIDEOMODE] = (void *) Mnormal;
 
   mface_normal_video = mface ();
   mface_normal_video->property[MFACE_VIDEOMODE] = (void *) Mnormal;
@@ -604,14 +602,19 @@ mface__realize (MFrame *frame, MFace **faces, int num, int size, MFont *font)
   MRealizedFace *rface;
   MRealizedFont *rfont;
   MFace merged_face = *(frame->face);
   MRealizedFace *rface;
   MRealizedFont *rfont;
   MFace merged_face = *(frame->face);
-  void **props;
   int i, j;
   MFaceHookFunc func;
   int i, j;
   MFaceHookFunc func;
-  MFont adjusted;
+  MFont spec;
 
   if (num == 0 && frame->rface && ! font)
     return frame->rface;
 
 
   if (num == 0 && frame->rface && ! font)
     return frame->rface;
 
+  if (! mplist_find_by_value (frame->face->frame_list, frame))
+    mplist_push (frame->face->frame_list, Mt, frame);
+  for (i = 0; i < num; i++)
+    if (! mplist_find_by_value (faces[i]->frame_list, frame))
+      mplist_push (faces[i]->frame_list, Mt, frame);
+
   for (i = 0; i < MFACE_PROPERTY_MAX; i++)
     for (j = num - 1; j >= 0; j--)
       if (faces[j]->property[i])
   for (i = 0; i < MFACE_PROPERTY_MAX; i++)
     for (j = num - 1; j >= 0; j--)
       if (faces[j]->property[i])
@@ -619,34 +622,27 @@ mface__realize (MFrame *frame, MFace **faces, int num, int size, MFont *font)
          merged_face.property[i] = faces[j]->property[i];
          break;
        }
          merged_face.property[i] = faces[j]->property[i];
          break;
        }
+
   if (font)
     {
   if (font)
     {
+      if (font->type != MFONT_TYPE_REALIZED)
+       font = mfont_copy (font);
       for (i = 0; i <= MFACE_ADSTYLE; i++)
        if (font->property[i])
          merged_face.property[i] = FONT_PROPERTY (font, i);
       if (font->size)
        {
       for (i = 0; i <= MFACE_ADSTYLE; i++)
        if (font->property[i])
          merged_face.property[i] = FONT_PROPERTY (font, i);
       if (font->size)
        {
-         if (font->size < 0)
-           {
-             double pt = - font->size;
+         int font_size;
 
 
-             adjusted = *font;
-             adjusted.size = pt * frame->dpi / 72.27 + 0.5;
-             font = &adjusted;
-           }
-         merged_face.property[MFACE_SIZE] = (void *) font->size;
+         if (font->size < 0)
+           font->size = ((double) (- font->size)) * frame->dpi / 72.27 + 0.5;
+         font_size = font->size;
+         merged_face.property[MFACE_SIZE] = (void *) font_size;
+         merged_face.property[MFACE_RATIO] = (void *) 0;
        }
     }
 
        }
     }
 
-  if (! mplist_find_by_value (frame->face->frame_list, frame))
-    mplist_push (frame->face->frame_list, Mt, frame);
-  for (i = 0; i < num; i++)
-    if (! mplist_find_by_value (faces[i]->frame_list, frame))
-      mplist_push (faces[i]->frame_list, Mt, frame);
-
-  if ((int) merged_face.property[MFACE_SIZE] < 0
-      || (merged_face.property[MFACE_RATIO]
-         && (int) merged_face.property[MFACE_RATIO] != 100))
+  if (! font || ! font->size)
     {
       double font_size = (int) merged_face.property[MFACE_SIZE];
       int ifont_size;
     {
       double font_size = (int) merged_face.property[MFACE_SIZE];
       int ifont_size;
@@ -658,72 +654,111 @@ mface__realize (MFrame *frame, MFace **faces, int num, int size, MFont *font)
        {
          font_size *= (int) merged_face.property[MFACE_RATIO];
          font_size /= 100;
        {
          font_size *= (int) merged_face.property[MFACE_RATIO];
          font_size /= 100;
-         merged_face.property[MFACE_RATIO] = 0;
        }
       ifont_size = font_size + 0.5;
       merged_face.property[MFACE_SIZE] = (void *) ifont_size;
        }
       ifont_size = font_size + 0.5;
       merged_face.property[MFACE_SIZE] = (void *) ifont_size;
+      merged_face.property[MFACE_RATIO] = (void *) 0;
     }
 
   merged_face.property[MFACE_FOUNDRY] = Mnil;
   rface = find_realized_face (frame, &merged_face, font);
   if (rface)
     }
 
   merged_face.property[MFACE_FOUNDRY] = Mnil;
   rface = find_realized_face (frame, &merged_face, font);
   if (rface)
-    return rface;
+    {
+      if (font && font->type != MFONT_TYPE_REALIZED)
+       free (font);
+      return rface;
+    }
 
   MSTRUCT_CALLOC (rface, MERROR_FACE);
   mplist_push (frame->realized_face_list, Mt, rface);
   rface->frame = frame;
   rface->face = merged_face;
 
   MSTRUCT_CALLOC (rface, MERROR_FACE);
   mplist_push (frame->realized_face_list, Mt, rface);
   rface->frame = frame;
   rface->face = merged_face;
+  rface->font = font;
+
   if (font)
     {
   if (font)
     {
-      rface->font = mfont ();
-      *rface->font = *font;
+      if (font->type == MFONT_TYPE_SPEC)
+       rfont = (MRealizedFont *) mfont_find (frame, font, NULL, 0);
+      else if (font->type == MFONT_TYPE_OBJECT)
+       {
+         MFONT_INIT (&spec);
+         spec.size = (int) merged_face.property[MFONT_SIZE];
+         if (font->property[MFONT_REGISTRY])
+           spec.property[MFONT_REGISTRY] = font->property[MFONT_REGISTRY];
+         else
+           mfont_put_prop (&spec, Mregistry,
+                           (font->source == MFONT_SOURCE_X
+                            ? Miso8859_1 : Municode_bmp));
+         rfont = mfont__open (frame, font, &spec);
+       }
+      else
+       rfont = (MRealizedFont *) font;
     }
     }
-  props = merged_face.property;
-  rface->rfontset = mfont__realize_fontset (frame,
-                                           (MFontset *) props[MFACE_FONTSET],
-                                           &merged_face, font);
-  num = 0;
-  rfont = NULL;
-  if (! font)
+  else
     {
     {
-      MFont spec;
+      MFontset *fontset = (MFontset *) merged_face.property[MFACE_FONTSET];
 
 
+      rface->rfontset = mfont__realize_fontset (frame, fontset, &merged_face,
+                                               font);
+      rfont = NULL;
       mfont__set_spec_from_face (&spec, &merged_face);
       mfont__set_spec_from_face (&spec, &merged_face);
-      mfont_put_prop (&spec, Mregistry, Miso8859_1);
-      spec.source = MFONT_SOURCE_X;
+      mfont_put_prop (&spec, Mregistry, Municode_bmp);
+      spec.source = MFONT_SOURCE_FT;
       font = mfont__select (frame, &spec, 0);
       if (font)
        rfont = mfont__open (frame, font, &spec);
       if (! rfont)
        {
       font = mfont__select (frame, &spec, 0);
       if (font)
        rfont = mfont__open (frame, font, &spec);
       if (! rfont)
        {
-         mfont_put_prop (&spec, Mregistry, Municode_bmp);
-         spec.source = MFONT_SOURCE_FT;
+         mfont_put_prop (&spec, Mregistry, Miso8859_1);
+         spec.source = MFONT_SOURCE_X;
          font = mfont__select (frame, &spec, 0);
          if (font)
            rfont = mfont__open (frame, font, &spec);
        }
          font = mfont__select (frame, &spec, 0);
          if (font)
            rfont = mfont__open (frame, font, &spec);
        }
+      if (! rfont)
+       {
+         num = 0;
+         rfont = mfont__lookup_fontset (rface->rfontset, NULL, &num,
+                                        Mlatin, Mnil, Mnil, size, 0);
+       }
     }
     }
-  if (! rfont)
-    rfont = mfont__lookup_fontset (rface->rfontset, NULL, &num,
-                                  Mlatin, Mnil, Mnil, size, 0);
+
   if (rfont)
     {
       rface->rfont = rfont;
       rface->layouter = rfont->layouter;
   if (rfont)
     {
       rface->rfont = rfont;
       rface->layouter = rfont->layouter;
+      rfont->layouter = Mnil;
       work_gstring.glyphs[0].rface = rface;
       work_gstring.glyphs[0].rface = rface;
-      work_gstring.glyphs[0].code = MCHAR_INVALID_CODE;
+      work_gstring.glyphs[0].g.code = MCHAR_INVALID_CODE;
+      work_gstring.glyphs[0].g.measured = 0;
       mfont__get_metric (&work_gstring, 0, 1);
       mfont__get_metric (&work_gstring, 0, 1);
-      rface->ascent = work_gstring.glyphs[0].ascent;
-      rface->descent = work_gstring.glyphs[0].descent;
-      work_gstring.glyphs[0].code
+      rface->ascent = work_gstring.glyphs[0].g.ascent;
+      rface->descent = work_gstring.glyphs[0].g.descent;
+      work_gstring.glyphs[0].g.code
        = mfont__encode_char (frame, (MFont *) rfont, NULL, ' ');
        = mfont__encode_char (frame, (MFont *) rfont, NULL, ' ');
-      if (work_gstring.glyphs[0].code != MCHAR_INVALID_CODE)
+      if (work_gstring.glyphs[0].g.code != MCHAR_INVALID_CODE)
        {
        {
+         work_gstring.glyphs[0].g.measured = 0;
          mfont__get_metric (&work_gstring, 0, 1);
          mfont__get_metric (&work_gstring, 0, 1);
-         rface->space_width = work_gstring.glyphs[0].width;
+         rface->space_width = work_gstring.glyphs[0].g.xadv;
        }
       else
        rface->space_width = rfont->spec.size / 10;
        }
       else
        rface->space_width = rfont->spec.size / 10;
+      if (rfont->average_width)
+       rface->average_width = rfont->average_width >> 6;
+      else
+       {
+         work_gstring.glyphs[0].g.code
+           = mfont__encode_char (frame, (MFont *) rfont, NULL, 'x');
+         if (work_gstring.glyphs[0].g.code != MCHAR_INVALID_CODE)
+           {
+             work_gstring.glyphs[0].g.measured = 0;
+             mfont__get_metric (&work_gstring, 0, 1);
+             rface->average_width = work_gstring.glyphs[0].g.xadv;
+           }
+         else
+           rface->average_width = rface->space_width;
+       }
     }
   else
     {
     }
   else
     {
@@ -731,16 +766,16 @@ mface__realize (MFrame *frame, MFace **faces, int num, int size, MFont *font)
       rface->space_width = frame->space_width;
     }
 
       rface->space_width = frame->space_width;
     }
 
-  rface->hline = (MFaceHLineProp *) props[MFACE_HLINE];
+  rface->hline = (MFaceHLineProp *) merged_face.property[MFACE_HLINE];
   if (rface->hline && rface->hline->width == 0)
     rface->hline = NULL;
   if (rface->hline && rface->hline->width == 0)
     rface->hline = NULL;
-  rface->box = (MFaceBoxProp *) props[MFACE_BOX];
+  rface->box = (MFaceBoxProp *) merged_face.property[MFACE_BOX];
   if (rface->box && rface->box->width == 0)
     rface->box = NULL;
   rface->ascii_rface = rface;
   (*frame->driver->realize_face) (rface);
 
   if (rface->box && rface->box->width == 0)
     rface->box = NULL;
   rface->ascii_rface = rface;
   (*frame->driver->realize_face) (rface);
 
-  func = (MFaceHookFunc) rface->face.property[MFACE_HOOK_FUNC];
+  func = rface->face.hook;
   if (func && func != noop_hook)
     (func) (&(rface->face), rface->info, rface->face.property[MFACE_HOOK_ARG]);
 
   if (func && func != noop_hook)
     (func) (&(rface->face), rface->info, rface->face.property[MFACE_HOOK_ARG]);
 
@@ -764,33 +799,99 @@ MGlyph *
 mface__for_chars (MSymbol script, MSymbol language, MSymbol charset,
                  MGlyph *from_g, MGlyph *to_g, int size)
 {
 mface__for_chars (MSymbol script, MSymbol language, MSymbol charset,
                  MGlyph *from_g, MGlyph *to_g, int size)
 {
-  MRealizedFont *rfont;
+  MRealizedFont *rfont = from_g->rface->rfont;
   MSymbol layouter;
   int num = to_g - from_g;
   int i;
 
   MSymbol layouter;
   int num = to_g - from_g;
   int i;
 
-  rfont = from_g->rface->rfont;
-  if (script == Mlatin)
+  if (from_g->rface->font)
+    {
+      MRealizedFace *rface = from_g->rface, *new;
+
+      if (! rfont)
+       rfont = mfontset__get_font (rface->frame,
+                                   rface->face.property[MFACE_FONTSET], 
+                                   script, language,
+                                   rface->font, NULL);
+      else if (script != Mlatin)
+       rfont = mfontset__get_font (rface->frame,
+                                   rface->face.property[MFACE_FONTSET],
+                                   script, language,
+                                   (MFont *) rfont, NULL);
+      if (! rfont)
+       {
+         for (; from_g < to_g && from_g->rface->font; from_g++)
+           from_g->g.code = MCHAR_INVALID_CODE;
+       }
+      else
+       {
+         if (rface->rfont == rfont && rfont->layouter == Mnil)
+           new = rface;
+         else
+           {
+             MSTRUCT_MALLOC (new, MERROR_FACE);
+             mplist_push (rface->non_ascii_list, Mt, new);
+             *new = *rface;
+             new->rfont = rfont;
+             new->layouter = rfont->layouter;
+             rfont->layouter = Mnil;
+             new->non_ascii_list = NULL;
+             new->ascent = rfont->ascent >> 6;
+             new->descent = rfont->descent >> 6;
+           } 
+         for (; from_g < to_g && from_g->rface->font; from_g++)
+           {
+             from_g->rface = new;
+             if (new->layouter)
+               {
+                 MFLT *flt = mflt_get (new->layouter);
+                 MCharTable *coverage;
+
+                 if (! flt
+                     || ((coverage = mflt_coverage (flt))
+                         && ! (from_g->g.code
+                               = (unsigned) mchartable_lookup (coverage,
+                                                               from_g->g.c))))
+                   {
+                     from_g->rface = rface;
+                     from_g->g.code = mfont__encode_char (rfont->frame, 
+                                                          (MFont *) rfont,
+                                                          NULL, from_g->g.c);
+                   }
+               }
+             else
+               from_g->g.code = mfont__encode_char (rfont->frame, 
+                                                    (MFont *) rfont,
+                                                    NULL, from_g->g.c);
+           }
+       }
+      return from_g;
+    }
+
+  if (rfont && script == Mlatin)
     {
       for (i = 0; i < num; i++)
        {
          unsigned code = mfont__encode_char (rfont->frame, (MFont *) rfont,
     {
       for (i = 0; i < num; i++)
        {
          unsigned code = mfont__encode_char (rfont->frame, (MFont *) rfont,
-                                             NULL, from_g[i].c);
+                                             NULL, from_g[i].g.c);
          if (code == MCHAR_INVALID_CODE)
            break;
          if (code == MCHAR_INVALID_CODE)
            break;
-         from_g[i].code = code;
+         from_g[i].g.code = code;
        }
        }
-      if (i == num)
-       return to_g;
+      if (i == num || from_g[i].rface->font)
+       return from_g + i;
     }
 
   rfont = mfont__lookup_fontset (from_g->rface->rfontset, from_g, &num,
                                 script, language, charset, size, 0);
   if (rfont)
     }
 
   rfont = mfont__lookup_fontset (from_g->rface->rfontset, from_g, &num,
                                 script, language, charset, size, 0);
   if (rfont)
-    layouter = rfont->layouter;
+    {
+      layouter = rfont->layouter;
+      rfont->layouter = Mnil;
+    }
   else
     {
   else
     {
-      from_g->code = MCHAR_INVALID_CODE;
+      from_g->g.code = MCHAR_INVALID_CODE;
       num = 1;
       rfont = NULL;
       layouter = Mnil;
       num = 1;
       rfont = NULL;
       layouter = Mnil;
@@ -826,8 +927,8 @@ mface__for_chars (MSymbol script, MSymbol language, MSymbol charset,
              new->non_ascii_list = NULL;
              if (rfont)
                {
              new->non_ascii_list = NULL;
              if (rfont)
                {
-                 new->ascent = rfont->ascent;
-                 new->descent = rfont->descent;
+                 new->ascent = rfont->ascent >> 6;
+                 new->descent = rfont->descent >> 6;
                }
            }
          while (g < from_g)
                }
            }
          while (g < from_g)
@@ -846,7 +947,7 @@ mface__free_realized (MRealizedFace *rface)
   MPLIST_DO (plist, rface->non_ascii_list)
     free (MPLIST_VAL (plist));
   M17N_OBJECT_UNREF (rface->non_ascii_list);
   MPLIST_DO (plist, rface->non_ascii_list)
     free (MPLIST_VAL (plist));
   M17N_OBJECT_UNREF (rface->non_ascii_list);
-  if (rface->font)
+  if (rface->font && rface->font->type != MFONT_TYPE_REALIZED)
     free (rface->font);
   free (rface);
 }
     free (rface->font);
   free (rface);
 }
@@ -857,6 +958,7 @@ mface__update_frame_face (MFrame *frame)
   frame->rface = NULL;
   frame->rface = mface__realize (frame, NULL, 0, 0, NULL);
   frame->space_width = frame->rface->space_width;
   frame->rface = NULL;
   frame->rface = mface__realize (frame, NULL, 0, 0, NULL);
   frame->space_width = frame->rface->space_width;
+  frame->average_width = frame->rface->average_width;
   frame->ascent = frame->rface->ascent;
   frame->descent = frame->rface->descent;
 }
   frame->ascent = frame->rface->ascent;
   frame->descent = frame->rface->descent;
 }
@@ -921,13 +1023,13 @@ MSymbol Mbackground;
     @brief Key of a face property specifying video mode.
 
     The variable #Mvideomode is used as a key of face property.  The
     @brief Key of a face property specifying video mode.
 
     The variable #Mvideomode is used as a key of face property.  The
-    property value must be #Mnormal, #Mreverse, or #Mnil.
+    property value must be @b Mnormal, @b Mreverse, or #Mnil.
 
 
-    #Mnormal means that an M-text is drawn in normal video mode
+    @b Mnormal means that an M-text is drawn in normal video mode
     (i.e. the foreground is drawn by foreground color, the background
     is drawn by background color).
 
     (i.e. the foreground is drawn by foreground color, the background
     is drawn by background color).
 
-    #Mreverse means that an M-text is drawn in reverse video mode
+    @b Mreverse means that an M-text is drawn in reverse video mode
     (i.e. the foreground is drawn by background color, the background
     is drawn by foreground color).
 
     (i.e. the foreground is drawn by background color, the background
     is drawn by foreground color).
 
@@ -936,12 +1038,12 @@ MSymbol Mbackground;
     @brief ¥Ó¥Ç¥ª¥â¡¼¥É¤ò»ØÄꤹ¤ë¤¿¤á¤Î¥Õ¥§¡¼¥¹¥×¥í¥Ñ¥Æ¥£¡¼¤Î¥­¡¼.
 
     ÊÑ¿ô #Mvideomode ¤Ï¥Õ¥§¡¼¥¹¥×¥í¥Ñ¥Æ¥£¤Î¥­¡¼¤È¤·¤ÆÍѤ¤¤é¤ì¤ë¡£¥×¥í¥Ñ¥Æ¥£¤ÎÃͤϡ¢
     @brief ¥Ó¥Ç¥ª¥â¡¼¥É¤ò»ØÄꤹ¤ë¤¿¤á¤Î¥Õ¥§¡¼¥¹¥×¥í¥Ñ¥Æ¥£¡¼¤Î¥­¡¼.
 
     ÊÑ¿ô #Mvideomode ¤Ï¥Õ¥§¡¼¥¹¥×¥í¥Ñ¥Æ¥£¤Î¥­¡¼¤È¤·¤ÆÍѤ¤¤é¤ì¤ë¡£¥×¥í¥Ñ¥Æ¥£¤ÎÃͤϡ¢
-    #Mnormal, #Mreverse, #Mnil ¤Î¤¤¤º¤ì¤«¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
+    @b Mnormal, @b Mreverse, #Mnil ¤Î¤¤¤º¤ì¤«¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
 
 
-    #Mnormal ¤Î¾ì¹ç¤Ï¡¢M-text 
+    @b Mnormal ¤Î¾ì¹ç¤Ï¡¢M-text 
     ¤òɸ½à¤Î¥Ó¥Ç¥ª¥â¡¼¥É¡ÊÁ°·Ê¤òÁ°·Ê¿§¤Ç¡¢ÇطʤòÇØ·Ê¿§¤Ç¡Ë¤Çɽ¼¨¤¹¤ë¡£
 
     ¤òɸ½à¤Î¥Ó¥Ç¥ª¥â¡¼¥É¡ÊÁ°·Ê¤òÁ°·Ê¿§¤Ç¡¢ÇطʤòÇØ·Ê¿§¤Ç¡Ë¤Çɽ¼¨¤¹¤ë¡£
 
-    #Mreverse ¤Î¾ì¹ç¤Ï¥ê¥Ð¡¼¥¹¥Ó¥Ç¥ª¥â¡¼¥É¤Ç¡ÊÁ°·Ê¤òÇØ·Ê¿§¤Ç¡¢ÇطʤòÁ°·Ê¿§¤Ç¡Ëɽ¼¨¤¹¤ë¡£
+    @b Mreverse ¤Î¾ì¹ç¤Ï¥ê¥Ð¡¼¥¹¥Ó¥Ç¥ª¥â¡¼¥É¤Ç¡ÊÁ°·Ê¤òÇØ·Ê¿§¤Ç¡¢ÇطʤòÁ°·Ê¿§¤Ç¡Ëɽ¼¨¤¹¤ë¡£
 
     #Mnil ¤Î¾ì¹ç¤Ï¥Ó¥Ç¥ª¥â¡¼¥É¤Ï»ØÄꤵ¤ì¤Ê¤¤¡£
     */
 
     #Mnil ¤Î¾ì¹ç¤Ï¥Ó¥Ç¥ª¥â¡¼¥É¤Ï»ØÄꤵ¤ì¤Ê¤¤¡£
     */
@@ -1074,7 +1176,6 @@ MSymbol Mhook_arg;
 /***en @name Variables: Possible values of #Mvideomode property of face */
 /***ja @name ÊÑ¿ô¡§  ¥Õ¥§¡¼¥¹¤Î #Mvideomode ¥×¥í¥Ñ¥Æ¥£¤Î²Äǽ¤ÊÃÍ */
 /*** @{ */
 /***en @name Variables: Possible values of #Mvideomode property of face */
 /***ja @name ÊÑ¿ô¡§  ¥Õ¥§¡¼¥¹¤Î #Mvideomode ¥×¥í¥Ñ¥Æ¥£¤Î²Äǽ¤ÊÃÍ */
 /*** @{ */
-/*=*/
 
 /***en
     See the documentation of the variable #Mvideomode.  */ 
 
 /***en
     See the documentation of the variable #Mvideomode.  */ 
@@ -1095,14 +1196,14 @@ MSymbol Mreverse;
     @brief Normal video face.
 
     The variable #mface_normal_video points to a face that has the
     @brief Normal video face.
 
     The variable #mface_normal_video points to a face that has the
-    #Mvideomode property with value #Mnormal.  The other properties
+    #Mvideomode property with value @b Mnormal.  The other properties
     are not specified.  An M-text drawn with this face appear normal
     colors (i.e. the foreground is drawn by foreground color, and
     background is drawn by background color).  */
 /***ja
     @brief É¸½à¥Ó¥Ç¥ª¥Õ¥§¡¼¥¹.
 
     are not specified.  An M-text drawn with this face appear normal
     colors (i.e. the foreground is drawn by foreground color, and
     background is drawn by background color).  */
 /***ja
     @brief É¸½à¥Ó¥Ç¥ª¥Õ¥§¡¼¥¹.
 
-    ÊÑ¿ô #mface_normal_video ¤Ï #Mvideomode ¥×¥í¥Ñ¥Æ¥£¤ÎÃͤ¬ #Mnormal 
+    ÊÑ¿ô #mface_normal_video ¤Ï #Mvideomode ¥×¥í¥Ñ¥Æ¥£¤ÎÃͤ¬ @b Mnormal 
     ¤Ç¤¢¤ë¥Õ¥§¡¼¥¹¤ò»Ø¤¹¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¡£Â¾¤Î¥×¥í¥Ñ¥Æ¥£¤Ï»ØÄꤵ¤ì¤Ê¤¤¡£
     ¤³¤Î¥Õ¥§¡¼¥¹¤Çɽ¼¨¤µ¤ì¤ëM-text 
     ¤Ïɸ½à¤Î¿§ (¤¹¤Ê¤ï¤ÁÁ°·Ê¤ÏÁ°·Ê¿§¡¢ÇطʤÏÇØ·Ê¿§¡Ë¤ÇÉÁ¤«¤ì¤ë¡£  */
     ¤Ç¤¢¤ë¥Õ¥§¡¼¥¹¤ò»Ø¤¹¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¡£Â¾¤Î¥×¥í¥Ñ¥Æ¥£¤Ï»ØÄꤵ¤ì¤Ê¤¤¡£
     ¤³¤Î¥Õ¥§¡¼¥¹¤Çɽ¼¨¤µ¤ì¤ëM-text 
     ¤Ïɸ½à¤Î¿§ (¤¹¤Ê¤ï¤ÁÁ°·Ê¤ÏÁ°·Ê¿§¡¢ÇطʤÏÇØ·Ê¿§¡Ë¤ÇÉÁ¤«¤ì¤ë¡£  */
@@ -1113,7 +1214,7 @@ MFace *mface_normal_video;
     @brief Reverse video face.
 
     The variable #mface_reverse_video points to a face that has the
     @brief Reverse video face.
 
     The variable #mface_reverse_video points to a face that has the
-    #Mvideomode property with value #Mreverse.  The other properties
+    #Mvideomode property with value @b Mreverse.  The other properties
     are not specified.  An M-text drawn with this face appear in
     reversed colors (i.e. the foreground is drawn by background
     color, and background is drawn by foreground color).  */
     are not specified.  An M-text drawn with this face appear in
     reversed colors (i.e. the foreground is drawn by background
     color, and background is drawn by foreground color).  */
@@ -1121,7 +1222,7 @@ MFace *mface_normal_video;
     @brief ¥ê¥Ð¡¼¥¹¥Ó¥Ç¥ª¥Õ¥§¡¼¥¹.
 
     ÊÑ¿ô #mface_reverse_video ¤Ï #Mvideomode ¥×¥í¥Ñ¥Æ¥£¤ÎÃͤ¬ 
     @brief ¥ê¥Ð¡¼¥¹¥Ó¥Ç¥ª¥Õ¥§¡¼¥¹.
 
     ÊÑ¿ô #mface_reverse_video ¤Ï #Mvideomode ¥×¥í¥Ñ¥Æ¥£¤ÎÃͤ¬ 
-    #Mreverse ¤Ç¤¢¤ë¥Õ¥§¡¼¥¹¤ò»Ø¤¹¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¡£Â¾¤Î¥×¥í¥Ñ¥Æ¥£¤Ï»ØÄꤵ¤ì¤Ê¤¤¡£
+    @b Mreverse ¤Ç¤¢¤ë¥Õ¥§¡¼¥¹¤ò»Ø¤¹¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¡£Â¾¤Î¥×¥í¥Ñ¥Æ¥£¤Ï»ØÄꤵ¤ì¤Ê¤¤¡£
     ¤³¤Î¥Õ¥§¡¼¥¹¤Çɽ¼¨¤µ¤ì¤ëM-text 
     ¤ÏÁ°·Ê¿§¤ÈÇØ·Ê¿§¤¬Æþ¤ìÂؤï¤Ã¤Æ (¤¹¤Ê¤ï¤ÁÁ°·Ê¤ÏÇØ·Ê¿§¡¢ÇطʤÏÁ°·Ê¿§¡ËÉÁ¤«¤ì¤ë¡£  */
 
     ¤³¤Î¥Õ¥§¡¼¥¹¤Çɽ¼¨¤µ¤ì¤ëM-text 
     ¤ÏÁ°·Ê¿§¤ÈÇØ·Ê¿§¤¬Æþ¤ìÂؤï¤Ã¤Æ (¤¹¤Ê¤ï¤ÁÁ°·Ê¤ÏÇØ·Ê¿§¡¢ÇطʤÏÁ°·Ê¿§¡ËÉÁ¤«¤ì¤ë¡£  */
 
@@ -1580,7 +1681,8 @@ mface_copy (MFace *face)
 
     The mface_equal () function compares faces $FACE1 and $FACE2.
 
 
     The mface_equal () function compares faces $FACE1 and $FACE2.
 
-    @return If two faces have the same property values, return 1.
+    @return
+    If two faces have the same property values, return 1.
     Otherwise return 0.  */
 
 int
     Otherwise return 0.  */
 
 int
@@ -1727,7 +1829,7 @@ mface_from_font (MFont *font)
 
         #Mforeground, #Mbackground, #Mvideomode, #Mhline, #Mbox,
         #Mfoundry, #Mfamily, #Mweight, #Mstyle, #Mstretch, #Madstyle,
 
         #Mforeground, #Mbackground, #Mvideomode, #Mhline, #Mbox,
         #Mfoundry, #Mfamily, #Mweight, #Mstyle, #Mstretch, #Madstyle,
-        #Msize, #Mfontset, #Mratio, #Mhook_func, #Mhook_arg
+        #Msize, #Mfontset, #Mratio, #Mhook_arg
 
     @return 
     Ìá¤êÃͤη¿¤Ï $KEY ¤Ë°Í¸¤¹¤ë¡£¾åµ­¤Î¥­¡¼¤ÎÀâÌÀ¤ò»²¾È¤¹¤ë¤³¤È¡£
 
     @return 
     Ìá¤êÃͤη¿¤Ï $KEY ¤Ë°Í¸¤¹¤ë¡£¾åµ­¤Î¥­¡¼¤ÎÀâÌÀ¤ò»²¾È¤¹¤ë¤³¤È¡£
@@ -1736,7 +1838,7 @@ mface_from_font (MFont *font)
 
 /***
     @seealso
 
 /***
     @seealso
-    mface_put_prop ()
+    mface_put_prop (), mface_put_hook ()
 
     @errors
     @c MERROR_FACE  */
 
     @errors
     @c MERROR_FACE  */
@@ -1747,13 +1849,37 @@ mface_get_prop (MFace *face, MSymbol key)
   int index = (int) msymbol_get (key, M_face_prop_index) - 1;
 
   if (index < 0)
   int index = (int) msymbol_get (key, M_face_prop_index) - 1;
 
   if (index < 0)
-    MERROR (MERROR_FACE, NULL);
+    {
+      if (key == Mhook_func)
+       /* This unsafe code is for backward compatiblity.  */
+       return (void *) face->hook;
+      MERROR (MERROR_FACE, NULL);
+    }
   return face->property[index];
 }
 
 /*=*/
 
 /***en
   return face->property[index];
 }
 
 /*=*/
 
 /***en
+    @brief Get the hook function of a face.
+
+    The mface_get_hook () function returns the hook function of face
+    $FACE.  */
+
+/***ja
+    @brief ¥Õ¥§¡¼¥¹¤Î¥Õ¥Ã¥¯´Ø¿ô¤òÆÀ¤ë.
+
+    ´Ø¿ô mface_get_hook () ¤Ï¥Õ¥§¡¼¥¹ $FACE ¤Î¥Õ¥Ã¥¯´Ø¿ô¤òÊÖ¤¹¡£ */
+
+MFaceHookFunc
+mface_get_hook (MFace *face)
+{
+  return face->hook;
+}
+
+/*=*/
+
+/***en
     @brief Set a value of a face property.
 
     The mface_put_prop () function assigns $VAL to the property whose
     @brief Set a value of a face property.
 
     The mface_put_prop () function assigns $VAL to the property whose
@@ -1808,22 +1934,32 @@ mface_put_prop (MFace *face, MSymbol key, void *val)
   int index = (int) msymbol_get (key, M_face_prop_index) - 1;
   MPlist *plist;
 
   int index = (int) msymbol_get (key, M_face_prop_index) - 1;
   MPlist *plist;
 
-  if (index < 0)
-    MERROR (MERROR_FACE, -1);
-  if (key == Mfontset)
+  if (key == Mhook_func)
     {
     {
-      if (face->property[index])
-       M17N_OBJECT_UNREF (face->property[index]);
-      M17N_OBJECT_REF (val);
+      /* This unsafe code is for backward compatiblity.  */
+      if (face->hook == (MFaceHookFunc) val)
+       return 0;
+      face->hook = (MFaceHookFunc) val;
     }
     }
-  else if (key == Mhline)
-    val = get_hline_create (val);
-  else if (key == Mbox)
-    val = get_box_create (val);
+  else
+    {
+      if (index < 0)
+       MERROR (MERROR_FACE, -1);
+      if (key == Mfontset)
+       {
+         if (face->property[index])
+           M17N_OBJECT_UNREF (face->property[index]);
+         M17N_OBJECT_REF (val);
+       }
+      else if (key == Mhline)
+       val = get_hline_create (val);
+      else if (key == Mbox)
+       val = get_box_create (val);
 
 
-  if (face->property[index] == val)
-    return 0;
-  face->property[index] = val;
+      if (face->property[index] == val)
+       return 0;
+      face->property[index] = val;
+    }
 
   MPLIST_DO (plist, face->frame_list)
     {
 
   MPLIST_DO (plist, face->frame_list)
     {
@@ -1840,6 +1976,40 @@ mface_put_prop (MFace *face, MSymbol key, void *val)
 /*=*/
 
 /***en
 /*=*/
 
 /***en
+    @brief Set a hook function to a face.
+
+    The mface_set_hook () function sets the hook function of face
+    $FACE to $FUNC.  */
+
+/***ja
+    @brief ¥Õ¥§¡¼¥¹¤Î¥Õ¥Ã¥¯´Ø¿ô¤òÀßÄꤹ¤ë.
+
+    ´Ø¿ô mface_set_hook () ¤Ï¡¢¥Õ¥§¡¼¥¹ $FACE ¤Î¥Õ¥Ã¥¯´Ø¿ô¤ò$FUNC ¤ËÀß
+    Äꤹ¤ë¡£  */
+
+int
+mface_put_hook (MFace *face, MFaceHookFunc func)
+{
+  if (face->hook != func)
+    {
+      MPlist *plist;
+      face->hook = func;
+
+      MPLIST_DO (plist, face->frame_list)
+       {
+         MFrame *frame = MPLIST_VAL (plist);
+
+         frame->tick++;
+         if (face == frame->face)
+           mface__update_frame_face (frame);
+       }
+    }
+  return 0;
+}
+
+/*=*/
+
+/***en
     @brief Update a face.
 
     The mface_update () function update face $FACE on frame $FRAME by
     @brief Update a face.
 
     The mface_update () function update face $FACE on frame $FRAME by
@@ -1854,7 +2024,7 @@ mface_put_prop (MFace *face, MSymbol key, void *val)
 void
 mface_update (MFrame *frame, MFace *face)
 {
 void
 mface_update (MFrame *frame, MFace *face)
 {
-  MFaceHookFunc func = (MFaceHookFunc) face->property[MFACE_HOOK_FUNC];
+  MFaceHookFunc func = face->hook;
   MPlist *rface_list;
   MRealizedFace *rface;
 
   MPlist *rface_list;
   MRealizedFace *rface;
 
@@ -1863,7 +2033,7 @@ mface_update (MFrame *frame, MFace *face)
       MPLIST_DO (rface_list, frame->realized_face_list)
        {
          rface = MPLIST_VAL (rface_list);
       MPLIST_DO (rface_list, frame->realized_face_list)
        {
          rface = MPLIST_VAL (rface_list);
-         if ((MFaceHookFunc) rface->face.property[MFACE_HOOK_FUNC] == func)
+         if (rface->face.hook == func)
            (func) (&(rface->face), rface->face.property[MFACE_HOOK_ARG],
                    rface->info);
        }
            (func) (&(rface->face), rface->face.property[MFACE_HOOK_ARG],
                    rface->info);
        }
@@ -1881,9 +2051,10 @@ mface_update (MFrame *frame, MFace *face)
 /***en
     @brief Dump a face.
 
 /***en
     @brief Dump a face.
 
-    The mdebug_dump_face () function prints face $FACE in a human readable
-    way to the stderr.  $INDENT specifies how many columns to indent
-    the lines but the first one.
+    The mdebug_dump_face () function prints face $FACE in a human
+    readable way to the stderr or to what specified by the environment
+    variable MDEBUG_OUTPUT_FILE.  $INDENT specifies how many columns
+    to indent the lines but the first one.
 
     @return
     This function returns $FACE.  */
 
     @return
     This function returns $FACE.  */
@@ -1891,8 +2062,9 @@ mface_update (MFrame *frame, MFace *face)
 /***ja
     @brief ¥Õ¥§¡¼¥¹¤ò¥À¥ó¥×¤¹¤ë.
 
 /***ja
     @brief ¥Õ¥§¡¼¥¹¤ò¥À¥ó¥×¤¹¤ë.
 
-    ´Ø¿ô mdebug_dump_face () ¤Ï¥Õ¥§¡¼¥¹ $FACE ¤ò stderr 
-    ¤Ë¿Í´Ö¤Ë²ÄÆɤʷÁ¤Ç°õºþ¤¹¤ë¡£ $INDENT ¤Ï£²¹ÔÌܰʹߤΥ¤¥ó¥Ç¥ó¥È¤ò»ØÄꤹ¤ë¡£
+    ´Ø¿ô mdebug_dump_face () ¤Ï¥Õ¥§¡¼¥¹ $FACE ¤òɸ½à¥¨¥é¡¼½ÐÎϤ⤷¤¯¤Ï
+    ´Ä¶­ÊÑ¿ô MDEBUG_DUMP_FONT ¤Ç»ØÄꤵ¤ì¤¿¥Õ¥¡¥¤¥ë¤Ë¿Í´Ö¤Ë²ÄÆɤʷÁ¤Ç°õ
+    ºþ¤¹¤ë¡£ $INDENT ¤Ï£²¹ÔÌܰʹߤΥ¤¥ó¥Ç¥ó¥È¤ò»ØÄꤹ¤ë¡£
 
     @return
     ¤³¤Î´Ø¿ô¤Ï $FACE ¤òÊÖ¤¹¡£  */
 
     @return
     ¤³¤Î´Ø¿ô¤Ï $FACE ¤òÊÖ¤¹¡£  */
@@ -1906,15 +2078,17 @@ mdebug_dump_face (MFace *face, int indent)
   memset (prefix, 32, indent);
   prefix[indent] = 0;
   mfont__set_spec_from_face (&spec, face);
   memset (prefix, 32, indent);
   prefix[indent] = 0;
   mfont__set_spec_from_face (&spec, face);
-  fprintf (stderr, "(face font:\"");
+  fprintf (mdebug__output, "(face font:\"");
   mdebug_dump_font (&spec);
   mdebug_dump_font (&spec);
-  fprintf (stderr, "\"\n %s  fore:%s back:%s", prefix,
+  fprintf (mdebug__output, "\"\n %s  fore:%s back:%s", prefix,
           msymbol_name ((MSymbol) face->property[MFACE_FOREGROUND]),
           msymbol_name ((MSymbol) face->property[MFACE_BACKGROUND]));
   if (face->property[MFACE_FONTSET])
           msymbol_name ((MSymbol) face->property[MFACE_FOREGROUND]),
           msymbol_name ((MSymbol) face->property[MFACE_BACKGROUND]));
   if (face->property[MFACE_FONTSET])
-    fprintf (stderr, " non-default-fontset");
-  fprintf (stderr, " hline:%s", face->property[MFACE_HLINE] ? "yes" : "no");
-  fprintf (stderr, " box:%s)", face->property[MFACE_BOX] ? "yes" : "no");
+    fprintf (mdebug__output, " non-default-fontset");
+  fprintf (mdebug__output, " hline:%s",
+          face->property[MFACE_HLINE] ? "yes" : "no");
+  fprintf (mdebug__output, " box:%s)",
+          face->property[MFACE_BOX] ? "yes" : "no");
   return face;
 }
 
   return face;
 }