(config_command): Fix previous change again.
[m17n/m17n-lib.git] / src / draw.c
index 241d07b..6155d4a 100644 (file)
@@ -1,5 +1,5 @@
 /* draw.c -- drawing module.
-   Copyright (C) 2003, 2004
+   Copyright (C) 2003, 2004, 2005, 2006
      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
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    02111-1307, USA.  */
 
 /***en
@@ -64,6 +64,7 @@
 #include "m17n-misc.h"
 #include "internal.h"
 #include "symbol.h"
+#include "mtext.h"
 #include "textprop.h"
 #include "internal-gui.h"
 #include "face.h"
 static MSymbol M_glyph_string;
 
 /* Special scripts */
-static MSymbol Minherited;
+static MSymbol Mcommon;
 /* Special categories */
 static MSymbol McatCc, McatCf;
 
+static MCharTable *linebreak_table;
+static MSymbol M_break_at_space, M_break_at_word, M_break_at_any;
+static MSymbol M_kinsoku_bol, M_kinsoku_eol;
+
 \f
 /* Glyph-string composer.  */
 
@@ -92,6 +97,7 @@ static MSymbol MbidiRLE;
 static MSymbol MbidiRLO;
 static MSymbol MbidiBN;
 static MSymbol MbidiS;
+static MSymbol MbidiNSM;
 
 static void
 visual_order (MGlyphString *gstring)
@@ -111,6 +117,8 @@ visual_order (MGlyphString *gstring)
   int *logical = alloca (sizeof (int) * len);
   int *indices;
   char *levels = alloca (len);
+
+  memset (levels, 0, sizeof (int) * len);
 #endif /* not HAVE_FRIBIDI */
 
   for (g = MGLYPH (1), i = 0; g->type != GLYPH_ANCHOR; g++, i++)
@@ -131,6 +139,10 @@ visual_order (MGlyphString *gstring)
              levels[i] = 1;
 #endif /* not HAVE_FRIBIDI */
            }
+#ifndef HAVE_FRIBIDI
+         else if (bidi == MbidiNSM && i > 0 && levels[i - 1])
+           levels[i] = 1;          
+#endif /* not HAVE_FRIBIDI */
        }
       logical[i] = g->c;
     }
@@ -178,7 +190,8 @@ visual_order (MGlyphString *gstring)
          /* Mirrored.  */
          g->c = visual[j];
          if (g->rface->rfont)
-           g->code = mfont__encode_char (g->rface->rfont, g->c);
+           g->code = mfont__encode_char (NULL, (MFont *) g->rface->rfont,
+                                         NULL, g->c);
        }
 #endif /* HAVE_FRIBIDI */
       g->bidi_level = levels[i];
@@ -231,7 +244,7 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
                      MGlyphString *gstring)
 {
   MRealizedFace *default_rface = frame->rface;
-  int stop, face_change, language_change, charset_change;
+  int stop, face_change, language_change, charset_change, font_change;
   MGlyph g_tmp, *g, *last_g;
   int pos;
   MSymbol language = Mnil, script = Mnil, charset = Mnil;
@@ -252,7 +265,7 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
   g_tmp.type = GLYPH_ANCHOR;
   g_tmp.pos = g_tmp.to = from;
   APPEND_GLYPH (gstring, g_tmp);
-  stop = face_change = pos = from;
+  stop = face_change = font_change = pos = from;
   while (1)
     {
       int c;
@@ -262,19 +275,39 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
        {
          if (pos == to)
            break;
-         if (pos == face_change)
+         if (pos < mtext_nchars (mt))
            {
+             MFont *font = rface->font;
              MFace *faces[64];
-             int num = mtext_get_prop_values (mt, pos, Mface,
-                                              (void **) faces, 64);
+             int num;
 
-             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);
+             if (pos == font_change)
+               {
+                 font = mtext_get_prop (mt, pos, Mfont);
+                 mtext_prop_range (mt, Mfont, pos, NULL, &font_change, 0);
+                 if (font_change == mtext_nchars (mt))
+                   font_change++;
+               }
+             if (pos == face_change)
+               {
+                 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++;
+               }
+             else
+               {
+                 faces[0] = &rface->face;
+                 num = 1;
+               }
+             rface = mface__realize (frame, faces, num, size, font);
            }
+         else
+           rface = default_rface;
          stop = to;
+         if (stop > font_change)
+           stop = font_change;         
          if (stop > face_change)
            stop = face_change;         
        }
@@ -334,11 +367,11 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
       else
        {
          this_script = (MSymbol) mchar_get_prop (c, Mscript);
-         if (this_script == Minherited || this_script == Mnil)
+         if (this_script == Minherited || this_script == Mcommon)
            this_script = script;
-         if (this_script == Mnil)
+         if (this_script == Mcommon)
            this_script = non_latin_script;
-         if (this_script == Mnil)
+         if (this_script == Mcommon)
            {
              /* Search forward for a character that explicitly
                 specifies a non-latin script.  */
@@ -347,7 +380,7 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
 
              for (g1 = g + 1; g1->type != GLYPH_ANCHOR; g1++)
                if (g1->c >= 0x100
-                   && (sym = mchar_get_prop (g1->c, Mscript)) != Mnil
+                   && (sym = mchar_get_prop (g1->c, Mscript)) != Mcommon
                    && sym != Minherited)
                  {
                    this_script = sym;
@@ -401,7 +434,7 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
        {
          int start = i++;
 
-         if (this->rface->rfont->layouter != Mnil)
+         if (this->rface->layouter != Mnil)
            {
              MGlyph *prev;
              unsigned code;
@@ -409,16 +442,25 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
              for (prev = MGLYPH (start - 1);
                   (prev->type == GLYPH_CHAR
                    && prev->category == GLYPH_CATEGORY_FORMATTER
-                   && (code = mfont__encode_char (this->rface->rfont, prev->c)
+                   && (code = mfont__encode_char (NULL,
+                                                  (MFont *) this->rface->rfont,
+                                                  NULL, prev->c)
                        != MCHAR_INVALID_CODE));
                   start--, prev--)
-               prev->code = code;
+               if (prev->rface->rfont != this->rface->rfont)
+                 {
+                   prev->rface->rfont = this->rface->rfont;
+                   prev->code = code;
+                 }
 
              for (g++;
                   (g->type == GLYPH_CHAR
+                   && g->rface->layouter == this->rface->layouter
                    && (g->rface->rfont == this->rface->rfont
                        || (g->category == GLYPH_CATEGORY_FORMATTER
-                           && ((code = mfont__encode_char (this->rface->rfont,
+                           && ((code = mfont__encode_char (NULL,
+                                                           (MFont *) this->rface->rfont,
+                                                           NULL,
                                                            g->c))
                                != MCHAR_INVALID_CODE))));
                   i++, g++)
@@ -546,7 +588,7 @@ layout_glyphs (MFrame *frame, MGlyphString *gstring, int from, int to,
     {
       MGlyph *base = g++;
       MRealizedFont *rfont = base->rface->rfont;
-      int size = rfont->font.property[MFONT_SIZE];
+      int size = rfont->spec.size;
       int width, lbearing, rbearing;
 
       if (g == last_g || ! g->combining_code)
@@ -570,7 +612,10 @@ layout_glyphs (MFrame *frame, MGlyphString *gstring, int from, int to,
          if (base->left_padding && base->lbearing < 0)
            {
              base->xoff = - base->lbearing;
-             base->width += base->xoff;
+             if (base->rbearing < 0)
+               base->width = base->rbearing - base->lbearing;
+             else
+               base->width += base->xoff;
              base->rbearing += base->xoff;
              base->lbearing = 0;
            }
@@ -578,9 +623,8 @@ layout_glyphs (MFrame *frame, MGlyphString *gstring, int from, int to,
            {
              base->width = base->rbearing;
            }
-         lbearing = (base->xoff + base->lbearing < 0
-                     ? base->xoff + base->lbearing : 0);
-         rbearing = base->xoff + base->rbearing;
+         lbearing = base->lbearing;
+         rbearing = base->rbearing;
        }
       else
        {
@@ -617,7 +661,7 @@ layout_glyphs (MFrame *frame, MGlyphString *gstring, int from, int to,
                                                   (combining_code));
 
                  rfont = g->rface->rfont;
-                 size = rfont->font.property[MFONT_SIZE];
+                 size = rfont->spec.size;
                  off_x = (size * (COMBINING_CODE_OFF_X (combining_code) - 128)
                           / 1000);
                  off_y = (size * (COMBINING_CODE_OFF_Y (combining_code) - 128)
@@ -682,6 +726,12 @@ layout_glyphs (MFrame *frame, MGlyphString *gstring, int from, int to,
              base[i].pos = begin;
              base[i].to = end;
            }
+         if (base->left_padding && lbearing < 0)
+           {
+             base->xoff -= lbearing;
+             base->width -= lbearing;
+             lbearing = 0;
+           }
        }
 
       g_physical_ascent = MAX (g_physical_ascent, base->ascent);
@@ -1062,6 +1112,7 @@ draw_background (MFrame *frame, MDrawWindow win, int x, int y,
     }
 
   *from_idx = *to_idx = 0;
+  *to_x = x;
   while (g->type != GLYPH_ANCHOR)
     {
       if (g->pos >= from && g->pos < to)
@@ -1230,7 +1281,8 @@ render_glyphs (MFrame *frame, MDrawWindow win, int x, int y, int width,
                gend--;
            }
          if (g != gend)
-           while (gend[-1].to == gend->to) gend++;
+           while (gend->type != GLYPH_ANCHOR && gend[-1].to == gend->to)
+             gend++;
        }
     }
 
@@ -1341,23 +1393,30 @@ find_overlapping_glyphs (MGlyphString *gstring, int *left, int *right,
 
 
 static int
-gstring_width (MGlyphString *gstring, int from, int to, int *rbearing)
+gstring_width (MGlyphString *gstring, int from, int to,
+              int *lbearing, int *rbearing)
 {
   MGlyph *g;
   int width;
 
   if (from <= gstring->from && to >= gstring->to)
     {
+      if (lbearing)
+       *lbearing = gstring->lbearing;
       if (rbearing)
        *rbearing = gstring->rbearing;
       return gstring->width;
     }
 
+  if (lbearing)
+    *lbearing = 0;
   if (rbearing)
     *rbearing = 0;
   for (g = MGLYPH (1), width = 0; g->type != GLYPH_ANCHOR; g++)
     if (g->pos >= from && g->pos < to)
       {
+       if (lbearing && width + g->lbearing < *lbearing)
+         *lbearing = width + g->lbearing;
        if (rbearing && width + g->rbearing > *rbearing)
          *rbearing = width + g->rbearing;
        width += g->width;
@@ -1376,8 +1435,10 @@ render_glyph_string (MFrame *frame, MDrawWindow win, int x, int y,
   int from_idx, to_idx;
   int to_x;
 
+  if (from == to)
+    return;
   if (control->orientation_reversed)
-    x -= gstring->indent + gstring_width (gstring, from, to, NULL);
+    x -= gstring->indent + gstring_width (gstring, from, to, NULL, NULL);
   else
     x += gstring->indent;
 
@@ -1493,6 +1554,9 @@ alloc_gstring (MFrame *frame, MText *mt, int pos, MDrawControl *control,
   return gstring;
 }
 
+static MGlyph *find_glyph_in_gstring (MGlyphString *gstring, int pos,
+                                     int forwardp);
+
 /* Truncate the line width of GSTRING to GSTRING->width_limit.  */
 
 static void
@@ -1526,16 +1590,26 @@ truncate_gstring (MFrame *frame, MText *mt, MGlyphString *gstring)
   if (gstring->control.line_break)
     {
       pos = (*gstring->control.line_break) (mt, gstring->from + i,
-                                           gstring->from, gstring->to, 0, 0);
+                                           gstring->from, gstring->from + i,
+                                           0, 0);
       if (pos <= gstring->from)
-       pos = gstring->from + 1;
+       {
+         g = find_glyph_in_gstring (gstring, gstring->from, 1);
+         pos = g->to;
+       }
       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);
+    {
+      g = find_glyph_in_gstring (gstring, gstring->from, 1);
+      pos = g->to;
+    }
+  if (pos < gstring->to)
+    {
+      compose_glyph_string (frame, mt, gstring->from, pos, gstring);
+      layout_glyph_string (frame, gstring);
+    }
 }
 
 
@@ -1806,7 +1880,7 @@ mdraw__init ()
   memset (&scratch_gstring, 0, sizeof (scratch_gstring));
   MLIST_INIT1 (&scratch_gstring, glyphs, 3);
 
-  Minherited = msymbol ("inherited");
+  Mcommon = msymbol ("common");
 
   McatCc = msymbol ("Cc");
   McatCf = msymbol ("Cf");
@@ -1817,10 +1891,17 @@ mdraw__init ()
   MbidiRLO = msymbol ("RLO");
   MbidiBN = msymbol ("BN");
   MbidiS = msymbol ("S");
+  MbidiNSM = msymbol ("NSM");
 #ifdef HAVE_FRIBIDI
   fribidi_set_mirroring (TRUE);
 #endif
 
+  M_break_at_space = msymbol ("bs");
+  M_break_at_word = msymbol ("bw");
+  M_break_at_any = msymbol ("ba");
+  M_kinsoku_bol = msymbol ("kb");
+  M_kinsoku_eol = msymbol ("ke");
+
   return 0;
 }
 
@@ -1828,6 +1909,8 @@ void
 mdraw__fini ()
 {
   MLIST_FREE1 (&scratch_gstring, glyphs);
+  M17N_OBJECT_UNREF (linebreak_table);
+  linebreak_table = NULL;
 }
 
 /*** @} */
@@ -2171,7 +2254,7 @@ mdraw_text_extents (MFrame *frame,
 {
   MGlyphString *gstring;
   int y = 0;
-  int width, rbearing;
+  int width, lbearing, rbearing;
 
   ASSURE_CONTROL (control);
   M_CHECK_POS_X (mt, from, -1);
@@ -2183,52 +2266,49 @@ mdraw_text_extents (MFrame *frame,
   gstring = get_gstring (frame, mt, from, to, control);
   if (! gstring)
     MERROR (MERROR_DRAW, -1);
-  width = gstring_width (gstring, from, to, &rbearing);
+  width = gstring_width (gstring, from, to, &lbearing, &rbearing);
   if (overall_ink_return)
-    {
-      overall_ink_return->y = - gstring->physical_ascent;
-      overall_ink_return->x = gstring->lbearing;
-    }
+    overall_ink_return->y = - gstring->physical_ascent;
   if (overall_logical_return)
-    {
-      overall_logical_return->y = - gstring->ascent;
-      overall_logical_return->x = 0;
-    }
+    overall_logical_return->y = - gstring->ascent;
   if (overall_line_return)
-    {
-      overall_line_return->y = - gstring->line_ascent;
-      overall_line_return->x = gstring->lbearing;
-    }
+    overall_line_return->y = - gstring->line_ascent;
 
   for (from = gstring->to; from < to; from = gstring->to)
     {
-      int this_width, this_rbearing;
+      int this_width, this_lbearing, this_rbearing;
 
       y += gstring->line_descent;
       M17N_OBJECT_UNREF (gstring->top);
       gstring = get_gstring (frame, mt, from, to, control);
-      this_width = gstring_width (gstring, from, to, &this_rbearing);
+      this_width = gstring_width (gstring, from, to,
+                                 &this_lbearing, &this_rbearing);
       y += gstring->line_ascent;
       if (width < this_width)
        width = this_width;
       if (rbearing < this_rbearing)
        rbearing = this_rbearing;
+      if (lbearing > this_lbearing)
+       lbearing = this_lbearing;
     }
   if (overall_ink_return)
     {
-      overall_ink_return->width = rbearing;
+      overall_ink_return->x = lbearing;
+      overall_ink_return->width = rbearing - lbearing;
       overall_ink_return->height
        = y + gstring->physical_descent - overall_ink_return->y;
     }
   if (overall_logical_return)
     {
+      overall_logical_return->x = 0;
       overall_logical_return->width = width;
       overall_logical_return->height
        = y + gstring->descent - overall_logical_return->y;
     }
   if (overall_line_return)
     {
-      overall_line_return->width = MAX (width, rbearing);
+      overall_line_return->x = lbearing;
+      overall_line_return->width = MAX (width, rbearing - lbearing);
       overall_line_return->height
        = y + gstring->line_descent - overall_line_return->y;
     }
@@ -2591,7 +2671,7 @@ mdraw_glyph_info (MFrame *frame, MText *mt, int from, int pos,
   info->metrics.height = gstring->height;
   info->metrics.width = - g->lbearing + g->width;
   if (g->rface->rfont)
-    info->font = &g->rface->rfont->font;
+    info->font = (MFont *) g->rface->rfont;
   else
     info->font = NULL;
   /* info->logical_width is calculated later.  */
@@ -2603,7 +2683,8 @@ mdraw_glyph_info (MFrame *frame, MText *mt, int from, int pos,
 
       info->prev_from = g_tmp->pos;
     }
-  else if (info->line_from > 0)
+  else if (info->line_from > 0
+          && gstring->from > 0)
     {
       /* The logically previous glyph is on the previous line.  */
       MGlyphString *gst = get_gstring (frame, mt, gstring->from - 1,
@@ -2796,8 +2877,11 @@ mdraw_glyph_list (MFrame *frame, MText *mt, int from, int to,
          glyphs->y_advance = 0;
          if (g->rface->rfont)
            {
-             glyphs->font = &g->rface->rfont->font;
-             glyphs->font_type = g->rface->rfont->type;
+             glyphs->font = (MFont *) g->rface->rfont;
+             glyphs->font_type
+               = (glyphs->font->source == MFONT_SOURCE_X ? Mx
+                  : g->rface->rfont->driver == &mfont__ft_driver ? Mfreetype
+                  : Mxft);
              glyphs->fontp = g->rface->rfont->fontp;
            }
          else
@@ -2863,23 +2947,33 @@ mdraw_text_items (MFrame *frame, MDrawWindow win, int x, int y,
 }
 
 /*=*/
-/***en 
-      @brief   calculate a line breaking position.
-
-      The function mdraw_default_line_break () calculates a line
-      breaking position based on the line number $LINE and the
-      coordinate $Y, when a line is too long to fit within the width
-      limit.  $POS is the position of the character next to the last
-      one that fits within the limit.  $FROM is the position of the
-      first character of the line, and $TO is the position of the last
-      character displayed on the line if there were not width limit.
-      $LINE and $Y are reset to 0 when a line is broken by a newline
-      character, and incremented each time when a long line is broken
-      because of the width limit.  
+/***en
+    @brief Option of line breaking for drawing text.
 
-      @return 
-      This function returns a character position to break the
-      line.
+    The variable #mdraw_line_break_option specifies line breaking
+    options by logical-or of the members of #MTextLineBreakOption.  It
+    controls the line breaking algorithm of the function
+    mdraw_default_line_break ().  */
+    
+int mdraw_line_break_option;
+
+/*=*/
+/***en 
+    @brief Calculate a line breaking position.
+
+    The function mdraw_default_line_break () calculates a line
+    breaking position based on the line number $LINE and the
+    coordinate $Y, when a line is too long to fit within the width
+    limit.  $POS is the position of the character next to the last one
+    that fits within the limit.  $FROM is the position of the first
+    character of the line, and $TO is the position of the last
+    character displayed on the line if there were not width limit.
+    $LINE and $Y are reset to 0 when a line is broken by a newline
+    character, and incremented each time when a long line is broken
+    because of the width limit.
+
+    @return This function returns a character position to break the
+    line.
 */
 
 /***ja 
@@ -2901,31 +2995,14 @@ int
 mdraw_default_line_break (MText *mt, int pos,
                          int from, int to, int line, int y)
 {
-  int c = mtext_ref_char (mt, pos);
-  int orig_pos = pos;
-
-  if (c == ' ' || c == '\t')
-    {
-      pos++;
-      while (pos < to
-            && ((c = mtext_ref_char (mt, pos)) == ' ' || c == '\t'))
-       pos++;
-    }
-  else
-    {
-      while (pos > from)
-       {
-         if (c == ' ' || c == '\t')
-           break;
-         pos--;
-         c = mtext_ref_char (mt, pos);
-       }
-      if (pos == from)
-       pos = orig_pos;
-      else
-       pos++;
-    }
-  return pos;
+  int p, after;
+
+  p = mtext_line_break (mt, pos, mdraw_line_break_option, &after);
+  if (p < from)
+    p = from;
+  else if (p >= to)
+    p = to;
+  return p;
 }
 
 /*=*/