4da7478f56106fa8c11f32928d08bb9302a9bbec
[m17n/m17n-lib.git] / src / draw.c
1 /* draw.c -- drawing module.
2    Copyright (C) 2003, 2004
3      National Institute of Advanced Industrial Science and Technology (AIST)
4      Registration Number H15PRO112
5
6    This file is part of the m17n library.
7
8    The m17n library is free software; you can redistribute it and/or
9    modify it under the terms of the GNU Lesser General Public License
10    as published by the Free Software Foundation; either version 2.1 of
11    the License, or (at your option) any later version.
12
13    The m17n library is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    Lesser General Public License for more details.
17
18    You should have received a copy of the GNU Lesser General Public
19    License along with the m17n library; if not, write to the Free
20    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21    02111-1307, USA.  */
22
23 /***en
24     @addtogroup m17nDraw
25     @brief Drawing M-texts on a window.
26
27     The m17n GUI API provides functions to draw M-texts.
28
29     The fonts used for drawing are selected automatically based on the
30     fontset and the properties of a face.  A face also specifies the
31     appearance of M-texts, i.e. font size, color, underline, etc.
32
33     The drawing format of M-texts can be controlled in a variety of
34     ways, which provides powerful 2-dimensional layouting
35     facility.  */
36
37 /***ja
38     @addtogroup m17nDraw
39     @brief M-text ¤ò¥¦¥£¥ó¥É¥¦¤ËÉÁ²è¤¹¤ë.
40
41     m17n-gui API ¤Ë¤Ï¡¢M-text ¤òɽ¼¨¤¹¤ë¤¿¤á¤Î´Ø¿ô¤¬ÍÑ°Õ¤µ¤ì¤Æ¤¤¤ë¡£
42
43     É½¼¨¤ËÍѤ¤¤é¤ì¤ë¥Õ¥©¥ó¥È¤Ï¡¢¥Õ¥©¥ó¥È¥»¥Ã¥È¤È face ¥×¥í¥Ñ¥Æ¥£¤Ë´ð¤Å
44     ¤¤¤Æ¼«Æ°Åª¤Ë·èÄꤵ¤ì¤ë¡£¤Þ¤¿¡¢¥Õ¥©¥ó¥È¤Î¥µ¥¤¥º¤ä¿§¤ä²¼Àþ¤Ê¤É¤Î¸«±É
45     ¤¨¤â face ¤Ë¤è¤Ã¤Æ·è¤Þ¤ë¡£
46
47     M-text ¤ÎÉÁ²è¥Õ¥©¡¼¥Þ¥Ã¥È¤Ï¿ÍͤÊÊýË¡¤ÇÀ©¸æ¤Ç¤­¤ë¤Î¤Ç¡¢¶¯ÎϤÊÆó¼¡
48     ¸µ¥ì¥¤¥¢¥¦¥Èµ¡Ç½¤¬¼Â¸½¤Ç¤­¤ë¡£
49     */
50
51 /*=*/
52
53 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
54 /*** @addtogroup m17nInternal
55      @{ */
56
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #include <ctype.h>
61 #include <sys/types.h>
62
63 #include "config.h"
64 #include "m17n-gui.h"
65 #include "m17n-misc.h"
66 #include "internal.h"
67 #include "symbol.h"
68 #include "textprop.h"
69 #include "internal-gui.h"
70 #include "face.h"
71 #include "font.h"
72
73 #ifdef HAVE_FRIBIDI
74 #include <fribidi/fribidi.h>
75 #endif /* HAVE_FRIBIDI */
76
77 #define MAX(x, y) ((x) > (y) ? (x) : (y))
78 #define MIN(x, y) ((x) < (y) ? (x) : (y))
79
80 static MSymbol M_glyph_string;
81
82 /* Special scripts */
83 static MSymbol Mlatin, Minherited;
84 /* Special categories */
85 static MSymbol McatCc, McatCf;
86
87 \f
88 /* Glyph-string composer.  */
89
90 static MSymbol MbidiR;
91 static MSymbol MbidiAL;
92 static MSymbol MbidiRLE;
93 static MSymbol MbidiRLO;
94 static MSymbol MbidiBN;
95 static MSymbol MbidiS;
96
97 static void
98 visual_order (MGlyphString *gstring)
99 {
100   int len = gstring->used - 2;
101   MGlyph *glyphs;
102   int *idx = alloca (sizeof (int) * len);
103   int gidx;
104   int bidi_sensitive = gstring->control.orientation_reversed;
105   int size = 0;
106   MGlyph *g = MGLYPH (1);
107   int i;
108 #ifdef HAVE_FRIBIDI
109   FriBidiCharType base = (gstring->control.orientation_reversed
110                           ? FRIBIDI_TYPE_RTL : FRIBIDI_TYPE_LTR);
111   FriBidiChar *logical = alloca (sizeof (FriBidiChar) * len);
112   FriBidiChar *visual;
113   FriBidiStrIndex *indices;
114   FriBidiLevel *levels = alloca (sizeof (FriBidiLevel) * len);
115 #else  /* not HAVE_FRIBIDI */
116   int *logical = alloca (sizeof (int) * len);
117   int *indices;
118   char *levels = alloca (len);
119 #endif /* not HAVE_FRIBIDI */
120
121   while (g->type != GLYPH_ANCHOR)
122     {
123       MSymbol bidi = (MSymbol) mchar_get_prop (g->c, Mbidi_category);
124
125       if (bidi == MbidiR || bidi == MbidiAL
126           || bidi == MbidiRLE || bidi == MbidiRLO)
127         {
128           bidi_sensitive = 1;
129           levels[size] = 1;
130         }
131       else
132         levels[size] = 0;
133       idx[size] = GLYPH_INDEX (g);
134       logical[size++] = g++->c;
135       while (g->type != GLYPH_ANCHOR && g->combining_code)
136         g++;
137     }
138
139   if (! bidi_sensitive)
140     return;
141
142   glyphs = alloca (sizeof (MGlyph) * gstring->used);
143   memcpy (glyphs, gstring->glyphs, (sizeof (MGlyph) * gstring->used));
144 #ifdef HAVE_FRIBIDI
145   visual = alloca (sizeof (FriBidiChar) * size);
146   indices = alloca (sizeof (FriBidiStrIndex) * size);
147
148   fribidi_log2vis (logical, size, &base, visual, NULL, indices, levels);
149 #else  /* not HAVE_FRIBIDI */
150   indices = alloca (sizeof (int) * size);
151   for (i = 0; i < size; i++)
152     {
153       if (levels[i])
154         {
155           int j, k;
156
157           for (j = i + 1; j < size && levels[j]; j++);
158           for (k = j--; i < k; i++, j--)
159             indices[i] = j;
160           i--;
161         }
162       else
163         indices[i] = i;
164     }
165 #endif /* not HAVE_FRIBIDI */
166
167   /* IDX are indices to gstring->glyphs[].  The glyphs for LOGICAL[N]
168      starts from gstring->glyphs[IDX[N]].
169
170      INDICES are indices to LOGICAL[].  The glyph for VISUAL[N] is
171      originally at LOGICAL[INDICES[N]].  */
172
173   for (i = 0, gidx = 1; i < size; i++)
174     {
175       int j = indices[i];
176       int k = idx[j];
177
178       glyphs[k].bidi_level = levels[j];
179 #ifdef HAVE_FRIBIDI
180       if (visual[i] != logical[j])
181         {
182           /* Mirrored.  */
183           glyphs[k].c = visual[i];
184           if (glyphs[k].rface->rfont)
185             glyphs[k].code = mfont__encode_char (glyphs[k].rface->rfont,
186                                                  glyphs[k].c);
187         }
188 #endif /* not HAVE_FRIBIDI */
189       *(MGLYPH (gidx)) = glyphs[k];
190       for (gidx++, k++;
191            k < gstring->used - 1 && glyphs[k].combining_code;
192            gidx++, k++)
193         {
194           glyphs[k].bidi_level = levels[j];
195           *(MGLYPH (gidx)) = glyphs[k];
196         }
197     }
198 }
199
200 static void
201 reorder_combining_chars (MGlyphString *gstring, int from, int to)
202 {
203   MGlyph *g, *gbeg = MGLYPH (from + 1), *gend = MGLYPH (to), temp;
204   int reordered = 1;
205   
206   while (reordered)
207     {
208       reordered = 0;
209       for (g = gbeg; g != gend; g++)
210         if (COMBINING_CODE_CLASS (g->combining_code) > 0
211             && (COMBINING_CODE_CLASS (g[-1].combining_code)
212                 > COMBINING_CODE_CLASS (g->combining_code)))
213           {
214             reordered = 1;
215             temp = *g;
216             *g = g[-1];
217             g[-1] = temp;
218           }
219     }
220 }
221
222
223 /** Scan M-text MT from FROM to TO, and compose glyphs in GSTRING for
224     displaying them on FRAME.
225
226     This function fills members <type>, <rface>, <c>, <pos>, <to>,
227     <code> of glyphs.  The other members are filled by
228     layout_glyph_string.  */
229
230 static void
231 compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
232                       MGlyphString *gstring)
233 {
234   MRealizedFace *default_rface = frame->rface;
235   int stop, face_change, language_change, charset_change;
236   MGlyph g_tmp, *g;
237   int pos;
238   MSymbol language = Mnil, script = Mnil, charset = Mnil;
239   MRealizedFace *rface = default_rface;
240   int size = gstring->control.fixed_width;
241   int i;
242   int last;
243
244   MLIST_RESET (gstring);
245   gstring->from = from;
246
247   /* At first generate glyphs while using the member <enabled> as a
248      flag for rface re-checking.  */
249   INIT_GLYPH (g_tmp);
250
251   /** Put anchor glyphs at the head and tail.  */
252   g_tmp.type = GLYPH_ANCHOR;
253   g_tmp.pos = g_tmp.to = from;
254   g_tmp.c = 0;
255   APPEND_GLYPH (gstring, g_tmp);
256
257   stop = face_change = charset_change = language_change = pos = from;
258   last = 0;
259   while (1)
260     {
261       int c;
262       MSymbol this_script;
263
264       if (pos < mtext_nchars (mt))
265         c = mtext_ref_char (mt, pos);
266       else
267         c = '\n';
268       if (c < 0x100)
269         {
270           /* Short cut for the obvious case.  */
271           g_tmp.category = Mnil;
272           if (c == ' ' || c == '\n' || c == '\t')
273             g_tmp.type = GLYPH_SPACE, this_script = Mnil;
274           else
275             g_tmp.type = GLYPH_CHAR, this_script = Mlatin;
276         }
277       else
278         {
279           g_tmp.category = mchar_get_prop (c, Mcategory);
280           g_tmp.type = GLYPH_CHAR;
281           this_script = (MSymbol) mchar_get_prop (c, Mscript);
282           if (this_script == Minherited || this_script == Mnil)
283             this_script = script;
284           if (this_script == Mnil)
285             /* Search forward for a character that explicitly
286                specifies a script.  */
287             for (i = pos + 1; i < to; i++)
288               {
289                 int c1 = mtext_ref_char (mt, i); 
290                 MSymbol sym = ((c1 > 0x20 && c1 < 0x100) ? Mlatin
291                                : mchar_get_prop (c1, Mscript));
292                 
293                 if (sym != Minherited && sym != Mnil)
294                   {
295                     this_script = sym;
296                     break;
297                   }
298               }
299         }
300
301       if (pos == stop || script != this_script
302           || MGLYPH (last)->type != g_tmp.type)
303         {
304           g = MGLYPH (last);
305           if (g->type != GLYPH_ANCHOR)
306             while (g < gstring->glyphs + gstring->used)
307               g = mface__for_chars (script, language, charset,
308                                     g, gstring->glyphs + gstring->used, size);
309           if (pos == to)
310             break;
311           last = gstring->used;
312           script = this_script;
313           if (pos == stop)
314             {
315               if (pos < mtext_nchars (mt) && pos == language_change)
316                 {
317                   language = (MSymbol) mtext_get_prop (mt, pos, Mlanguage);
318                   mtext_prop_range (mt, Mlanguage, pos, NULL,
319                                     &language_change, 0);
320                 }
321               if (pos < mtext_nchars (mt) && pos == charset_change)
322                 {
323                   charset = (MSymbol) mtext_get_prop (mt, pos, Mcharset);
324                   mtext_prop_range (mt, Mcharset, pos, NULL,
325                                     &charset_change, 0);
326                 }
327               if (pos < mtext_nchars (mt) && pos == face_change)
328                 {
329                   MFace *faces[64];
330                   int num = mtext_get_prop_values (mt, pos, Mface,
331                                                    (void **) faces, 64);
332
333                   mtext_prop_range (mt, Mface, pos, NULL, &face_change, 1);
334                   rface = (num > 0
335                            ? mface__realize (frame, faces, num,
336                                              language, charset, size)
337                            : default_rface);
338                 }
339               stop = to;
340               if (stop > language_change)
341                 stop = language_change;
342               if (stop > charset_change)
343                 stop = charset_change;
344               if (face_change < stop)
345                 stop = face_change;             
346             }
347         }
348
349       g_tmp.c = c;
350       g_tmp.pos = pos++;
351       g_tmp.to = pos;
352       g_tmp.rface = rface;
353       
354       if ((c <= 32 || c == 127) && g_tmp.type == GLYPH_CHAR)
355         {
356           MGlyph ctrl[2];
357
358           ctrl[0] = ctrl[1] = g_tmp;
359           ctrl[0].c = '^';
360           ctrl[1].c = c < ' ' ? c + 0x40 : '?';
361           mface__for_chars (Mlatin, language, charset, ctrl, ctrl + 2, size);
362           APPEND_GLYPH (gstring, ctrl[0]);
363           APPEND_GLYPH (gstring, ctrl[1]);
364         }
365       else
366         APPEND_GLYPH (gstring, g_tmp);
367       if (c == '\n'
368           && gstring->control.two_dimensional)
369         break;
370     }
371
372   /* Append an anchor glyph.  */
373   g_tmp.type = GLYPH_ANCHOR;
374   g_tmp.c = 0;
375   g_tmp.code = MCHAR_INVALID_CODE;
376   g_tmp.pos = g_tmp.to = pos;
377   g_tmp.rface = NULL;
378   APPEND_GLYPH (gstring, g_tmp);
379
380   gstring->to = pos;
381
382   /* Next, run FLT if necessary.  */
383   for (i = 1, g = MGLYPH (i); g->type != GLYPH_ANCHOR;)
384     {
385       MGlyph *this = g;
386
387       if (this->type == GLYPH_CHAR && this->rface->rfont)
388         {
389           int start = i++;
390
391           if (this->rface->rfont->layouter != Mnil)
392             {
393               MGlyph *prev;
394               unsigned code;
395
396               for (prev = MGLYPH (start - 1);
397                    (prev->type == GLYPH_CHAR
398                     && prev->category == McatCf
399                     && (code = mfont__encode_char (this->rface->rfont, prev->c)
400                         != MCHAR_INVALID_CODE));
401                    start--, prev--)
402                 prev->code = code;
403
404               for (g++;
405                    (g->type == GLYPH_CHAR
406                     && (g->rface->rfont == this->rface->rfont
407                         || (g->category == McatCf
408                             && ((code = mfont__encode_char (this->rface->rfont,
409                                                             g->c))
410                                 != MCHAR_INVALID_CODE))));
411                    i++, g++)
412                 if (g->rface->rfont != this->rface->rfont)
413                   {
414                     g->rface->rfont = this->rface->rfont;
415                     g->code = code;
416                   }
417               i = mfont__flt_run (gstring, start, i, this->rface);
418             }
419           else
420             {
421               while (this->type == GLYPH_CHAR
422                      && this->c >= 0x100
423                      && this->category
424                      && MSYMBOL_NAME (this->category)[0] == 'M'
425                      && this->rface->rfont
426                      && this->rface->rfont->layouter == Mnil)
427                 {
428                   int class = (int) mchar_get_prop (this->c,
429                                                     Mcombining_class);
430                   this->combining_code
431                     = MAKE_COMBINING_CODE_BY_CLASS (class);
432                   i++, this++;
433                 }
434               if (start + 1 < i)
435                 reorder_combining_chars (gstring, start, i);
436               if (this->type == GLYPH_ANCHOR)
437                 break;
438             }
439           g = MGLYPH (i);
440         }
441       else
442         i++, g++;
443     }
444
445   /* At last, reorder glyphs visually if necessary.  */
446   if (gstring->control.enable_bidi)
447     visual_order (gstring);
448 }
449
450
451 static int
452 combining_code_from_class (int class)
453 {
454   int code;
455
456   if (class < 200)
457     code = MAKE_COMBINING_CODE (3, 1, 3, 1, 128, 128);
458   else if (class == 200)        /* below left attached */
459     code = MAKE_COMBINING_CODE (2, 0, 0, 1, 128, 128);
460   else if (class == 202)        /* below attached*/
461     code = MAKE_COMBINING_CODE (2, 1, 0, 1, 128, 128);
462   else if (class == 204)        /* below right attached */
463     code = MAKE_COMBINING_CODE (2, 2, 0, 1, 128, 128);
464   else if (class == 208)        /* left attached */
465     code = MAKE_COMBINING_CODE (3, 0, 3, 2, 128, 128);
466   else if (class == 210)        /* right attached */
467     code = MAKE_COMBINING_CODE (3, 2, 3, 0, 128, 128);
468   else if (class == 212)        /* above left attached */
469     code = MAKE_COMBINING_CODE (0, 0, 2, 1, 128, 128);
470   else if (class == 214)        /* above attached */
471     code = MAKE_COMBINING_CODE (0, 1, 2, 1, 128, 128);
472   else if (class == 216)        /* above right attached */
473     code = MAKE_COMBINING_CODE (0, 2, 2, 1, 128, 128);
474   else if (class == 218)        /* below left */
475     code = MAKE_COMBINING_CODE (2, 0, 0, 1, 122, 128);
476   else if (class == 220)        /* below */
477     code = MAKE_COMBINING_CODE (2, 1, 0, 1, 122, 128);
478   else if (class == 222)        /* below right */
479     code = MAKE_COMBINING_CODE (2, 2, 0, 1, 122, 128);
480   else if (class == 224)        /* left */
481     code = MAKE_COMBINING_CODE (3, 0, 3, 2, 128, 122);
482   else if (class == 226)        /* right */
483     code = MAKE_COMBINING_CODE (3, 2, 3, 0, 128, 133);
484   else if (class == 228)        /* above left */
485     code = MAKE_COMBINING_CODE (0, 0, 2, 1, 133, 128);
486   else if (class == 230)        /* above */
487     code = MAKE_COMBINING_CODE (0, 1, 2, 1, 133, 128);
488   else if (class == 232)        /* above right */
489     code = MAKE_COMBINING_CODE (0, 2, 2, 1, 133, 128);
490   else if (class == 233)        /* double below */
491     code = MAKE_COMBINING_CODE (2, 2, 0, 2, 122, 128);
492   else if (class == 234)        /* double above */
493     code = MAKE_COMBINING_CODE (0, 2, 2, 2, 133, 128);
494   else if (class == 240)        /* iota subscript */
495     code = MAKE_COMBINING_CODE (2, 1, 0, 1, 122, 128);
496   else                          /* unknown */
497     code = MAKE_COMBINING_CODE (3, 1, 3, 1, 128, 128);
498   return code;
499 }
500
501
502 static void
503 layout_glyphs (MFrame *frame, MGlyphString *gstring, int from, int to)
504 {
505   int g_physical_ascent, g_physical_descent;
506   int g_width, g_lbearing, g_rbearing;
507   MGlyph *g = MGLYPH (from);
508   MGlyph *last_g = MGLYPH (to);
509
510   g_physical_ascent = gstring->physical_ascent;
511   g_physical_descent = gstring->physical_descent;
512   g_width = g_lbearing = g_rbearing = 0;
513
514   mfont__get_metric (gstring, from, to);
515
516 #ifdef HAVE_OTF
517   while (g < last_g)
518     {
519       MGlyph *base = g++;
520
521       if (base->otf_cmd)
522         {
523           while (g < last_g && base->otf_cmd == g->otf_cmd) g++;
524           mfont__ft_drive_gpos (gstring, GLYPH_INDEX (base), GLYPH_INDEX (g));
525         }
526     }
527   g = MGLYPH (from);
528 #endif
529
530   while (g < last_g)
531     {
532       MGlyph *base = g++;
533       MRealizedFont *rfont = base->rface->rfont;
534       int size = rfont->font.property[MFONT_SIZE];
535       int width, lbearing, rbearing;
536
537       if (g == last_g || ! g->combining_code)
538         {
539           /* No combining.  */
540           if (base->left_padding && base->lbearing < 0)
541             {
542               base->xoff = - base->lbearing;
543               base->width += base->xoff;
544               base->rbearing += base->xoff;
545               base->lbearing = 0;
546             }
547           if (base->right_padding && base->rbearing > base->width)
548             {
549               base->width = base->rbearing;
550             }
551           lbearing = (base->lbearing < 0 ? base->lbearing : 0);
552           rbearing = base->rbearing;
553         }
554       else
555         {
556           /* With combining glyphs.  */
557           int left = -base->width;
558           int right = 0;
559           int top = - base->ascent;
560           int bottom = base->descent;
561           int height = bottom - top;
562           int begin = base->pos;
563           int end = base->to;
564           int i;
565
566           width = base->width;
567           lbearing = (base->lbearing < 0 ? base->lbearing : 0);
568           rbearing = base->rbearing;
569
570           while (g != last_g && g->combining_code)
571             {
572               int combining_code, base_x, base_y, add_x, add_y, off_x, off_y;
573
574               combining_code = g->combining_code;
575               if (COMBINING_BY_CLASS_P (combining_code))
576                 g->combining_code = combining_code
577                   = combining_code_from_class (COMBINING_CODE_CLASS
578                                                (combining_code));
579
580               rfont = g->rface->rfont;
581               size = rfont->font.property[MFONT_SIZE];
582               off_x = (size * (COMBINING_CODE_OFF_X (combining_code) - 128)
583                        / 1000);
584               off_y = (size * (COMBINING_CODE_OFF_Y (combining_code) - 128)
585                        / 1000);
586               base_x = COMBINING_CODE_BASE_X (combining_code);
587               base_y = COMBINING_CODE_BASE_Y (combining_code);
588               add_x = COMBINING_CODE_ADD_X (combining_code);
589               add_y = COMBINING_CODE_ADD_Y (combining_code);
590
591               if (begin > g->pos)
592                 begin = g->pos;
593               else if (end < g->to)
594                 end = g->to;
595                 
596               g->xoff = left + (width * base_x - g->width * add_x) / 2 + off_x;
597               if (g->xoff < left)
598                 left = g->xoff;
599               if (g->xoff + g->width > right)
600                 right = g->xoff + g->width;
601               width = right - left;
602               if (g->xoff + g->lbearing < left + lbearing)
603                 lbearing = g->xoff + g->lbearing - left;
604               if (g->xoff + g->rbearing > left + rbearing)
605                 rbearing = g->xoff + g->rbearing - left;
606
607               if (base_y < 3)
608                 g->yoff = top + height * base_y / 2;
609               else
610                 g->yoff = 0;
611               if (add_y < 3)
612                 g->yoff -= (g->ascent + g->descent) * add_y / 2 - g->ascent;
613               g->yoff -= off_y;
614               if (g->yoff - g->ascent < top)
615                 top = g->yoff - g->ascent;
616               if (g->yoff + g->descent > bottom)
617                 bottom = g->yoff + g->descent;
618               height = bottom - top;
619
620               g->width = 0;
621               g++;
622             }
623
624           base->ascent = - top;
625           base->descent = bottom;
626           base->lbearing = lbearing;
627           base->rbearing = rbearing;
628           if (left < - base->width)
629             {
630               base->xoff = - base->width - left;
631               base->width += base->xoff;
632               base->rbearing += base->xoff;
633               base->lbearing += base->xoff;
634             }
635           if (right > 0)
636             {
637               base->width += right;
638               base->rbearing += right;
639               base->right_padding = 1;
640               for (i = 1; base + i != g; i++)
641                 base[i].xoff -= right;
642             }
643
644           for (i = 0; base + i != g; i++)
645             {
646               base[i].pos = begin;
647               base[i].to = end;
648             }
649         }
650
651       g_physical_ascent = MAX (g_physical_ascent, base->ascent);
652       g_physical_descent = MAX (g_physical_descent, base->descent);
653       g_lbearing = MIN (g_lbearing, g_width + lbearing);
654       g_rbearing = MAX (g_rbearing, g_width + rbearing);
655       g_width += base->width;
656     }
657
658   gstring->physical_ascent = g_physical_ascent;
659   gstring->physical_descent = g_physical_descent;
660   gstring->sub_width = g_width;
661   gstring->sub_lbearing = g_lbearing;
662   gstring->sub_rbearing = g_rbearing;
663 }
664
665
666 /** Decide the layout of glyphs in GSTRING.  Space glyphs are handled
667     by this function directly.  Character glyphs are handled by
668     layouter functions registered in font drivers.
669
670     This function fill-in all the remaining members of glyphs.  */
671
672 static void
673 layout_glyph_string (MFrame *frame, MGlyphString *gstring)
674 {
675   /* Default width of TAB.  */
676   int tab_width = frame->space_width * (gstring->control.tab_width
677                                         ? gstring->control.tab_width : 8);
678   int tab_found = 0;
679   MGlyph *g;
680   MGlyph pad;
681   MDrawControl *control = &(gstring->control);
682   int width;
683   MFaceBoxProp *box;
684   int box_line_height = 0;
685   int ignore_formatting_char = control->ignore_formatting_char;
686
687   gstring->ascent = gstring->descent = 0;
688   gstring->physical_ascent = gstring->physical_descent = 0;
689   gstring->width = gstring->lbearing = gstring->rbearing = 0;
690
691   g = MGLYPH (1);
692   box = NULL;
693   while (g->type != GLYPH_ANCHOR)
694     {
695       if (box != g->rface->box)
696         {
697           int gidx = GLYPH_INDEX (g);
698
699           if (box)
700             {
701               /* Insert the right side of the box.  That glyph belongs
702                  to the previous grapheme cluster.  */
703               MGlyph box_glyph = g[-1];
704
705               box_glyph.type = GLYPH_BOX;
706               box_glyph.width
707                 = (control->fixed_width
708                    ? frame->space_width
709                    : box->inner_hmargin + box->width + box->outer_hmargin);
710               box_glyph.lbearing = 0;
711               box_glyph.rbearing = box_glyph.width;
712               box_glyph.xoff = 0;
713               box_glyph.right_padding = 1;
714               gstring->width += box_glyph.width;
715               gstring->rbearing += box_glyph.width;
716               INSERT_GLYPH (gstring, gidx, box_glyph);
717               gidx++;
718               g = MGLYPH (gidx);
719             }
720           box = g->rface->box;
721           if (box)
722             {
723               /* Insert the left side of the box.  That glyph belongs
724                  to the following grapheme cluster.  */
725               MGlyph box_glyph = *g;
726               int box_height = (box->width
727                                 + box->inner_vmargin + box->outer_vmargin);
728
729               if (box_line_height < box_height)
730                 box_line_height = box_height;
731               box_glyph.type = GLYPH_BOX;
732               box_glyph.width
733                 = (control->fixed_width
734                    ? frame->space_width
735                    : box->inner_hmargin + box->width + box->outer_hmargin);
736               box_glyph.lbearing = 0;
737               box_glyph.rbearing = box_glyph.width;
738               box_glyph.xoff = 0;
739               box_glyph.left_padding = 1;
740               gstring->width += box_glyph.width;
741               gstring->rbearing += box_glyph.width;
742               INSERT_GLYPH (gstring, gidx, box_glyph);
743               gidx++;
744               g = MGLYPH (gidx);
745             }
746         }
747
748       if (g->category == McatCf && ignore_formatting_char)
749         g->type = GLYPH_SPACE;
750
751       if (g->type == GLYPH_CHAR)
752         {
753           MRealizedFace *rface = g->rface;
754           MRealizedFont *rfont = rface->rfont;
755           MGlyph *fromg = g;
756           int from = GLYPH_INDEX (g);
757
758           for (g++; g->type == GLYPH_CHAR; g++)
759             if (! rfont != ! g->rface->rfont
760                 || box != g->rface->box
761                 || ((fromg->code == MCHAR_INVALID_CODE)
762                     != (g->code == MCHAR_INVALID_CODE))
763                 || (g->category == McatCf && ignore_formatting_char))
764               break;
765           if (rfont && fromg->code != MCHAR_INVALID_CODE)
766             {
767               int extra_width;
768               int to = GLYPH_INDEX (g);
769
770               layout_glyphs (frame, gstring, from, to);
771               extra_width = - gstring->sub_lbearing;
772               if (extra_width > 0
773                   && (GLYPH_INDEX (g) > 1
774                       || control->align_head))
775                 {
776                   g = MGLYPH (from);
777                   pad = *g;
778                   pad.type = GLYPH_PAD;
779                   pad.xoff = 0;
780                   pad.lbearing = 0;
781                   pad.width = pad.rbearing = extra_width;
782                   INSERT_GLYPH (gstring, from, pad);
783                   to++;
784                   gstring->sub_lbearing = 0;
785                   gstring->sub_width += extra_width;
786                   gstring->sub_rbearing += extra_width;
787
788                   g = MGLYPH (from - 1);
789                   if (g->type == GLYPH_SPACE)
790                     {
791                       /* The pad just inserted is absorbed (maybe
792                          partially) by the previous space while
793                          keeping at least some space width.  For the
794                          moment, we use the arbitrary width 2-pixel.
795                          Perhaps, it should be decided by the current
796                          face, or a default value of the current
797                          frame, which is, however, not yet
798                          implemented.  */
799                       if (extra_width + 2 < g->width)
800                         {
801                           g->width -= extra_width;
802                         }
803                       else
804                         {
805                           extra_width -= g->width - 2;
806                           g->width = 2;
807                         }
808                       gstring->width -= extra_width;
809                       gstring->rbearing -= extra_width;
810                     }
811                 }
812
813               extra_width = gstring->sub_rbearing - gstring->sub_width;
814               if (extra_width > 0)
815                 {
816                   g = MGLYPH (to);
817                   if (g->type == GLYPH_SPACE && box == g->rface->box)
818                     {
819                       g--;
820                       pad = *g;
821                       pad.type = GLYPH_PAD;
822                       pad.xoff = 0;
823                       pad.lbearing = 0;
824                       pad.width = pad.rbearing = extra_width;
825                       INSERT_GLYPH (gstring, to, pad);
826                       to++;
827                     }
828                   else
829                     g[-1].width += extra_width;
830                   gstring->sub_width += extra_width;
831                 }
832
833               if (gstring->lbearing > gstring->width + gstring->sub_lbearing)
834                 gstring->lbearing = gstring->width + gstring->sub_lbearing;
835               if (gstring->rbearing < gstring->width + gstring->sub_rbearing)
836                 gstring->rbearing = gstring->width + gstring->sub_rbearing;
837               gstring->width += gstring->sub_width;
838               if (gstring->ascent < rface->ascent)
839                 gstring->ascent = rface->ascent;
840               if (gstring->descent < rface->descent)
841                 gstring->descent = rface->descent;
842               g = MGLYPH (to);
843             }
844           else
845             {
846               for (; fromg < g; fromg++)
847                 {
848                   if ((fromg->c >= 0x200B && fromg->c <= 0x200F)
849                       || (fromg->c >= 0x202A && fromg->c <= 0x202E))
850                     fromg->width = fromg->rbearing = 1;
851                   else
852                     fromg->width = fromg->rbearing = rface->space_width;
853                   fromg->xoff = fromg->lbearing = 0;
854                   fromg->ascent = fromg->descent = 0;
855                   gstring->width += fromg->width;
856                   gstring->rbearing += fromg->width;
857                 }
858               if (gstring->ascent < frame->rface->ascent)
859                 gstring->ascent = frame->rface->ascent;
860               if (gstring->descent < frame->descent)
861                 gstring->descent = frame->rface->descent;
862             }
863         }
864       else if (g->type == GLYPH_SPACE)
865         {
866           if (g->c == ' ')
867             g->width = g->rface->space_width;
868           else if (g->c == '\n')
869             {
870               g->width = control->cursor_width;
871               if (g->width)
872                 {
873                   if (control->cursor_bidi)
874                     g->width = 3;
875                   else if (g->width < 0)
876                     g->width = g->rface->space_width;
877                 }
878             }
879           else if (g->c == '\t')
880             {
881               g->width = tab_width - ((gstring->indent + gstring->width)
882                                       % tab_width);
883               tab_found = 1;
884             }
885           else
886             g->width = 1;
887           if (g[-1].type == GLYPH_PAD)
888             {
889               /* This space glyph absorbs (maybe partially) the
890                  previous padding glyph.  */
891               g->width -= g[-1].width;
892               if (g->width < 1)
893                 /* But, keep at least some space width.  For the
894                    moment, we use the arbitrary width 2-pixel.  */
895                 g->width = 2;
896             }
897           g->rbearing = g->width;
898           gstring->width += g->width;
899           gstring->rbearing += g->width;
900           if (g->rface->rfont)
901             {
902               if (gstring->ascent < g->rface->ascent)
903                 gstring->ascent = g->rface->ascent;
904               if (gstring->descent < g->rface->descent)
905                 gstring->descent = g->rface->descent;
906             }
907           g++;
908         }
909       else
910         {
911           gstring->width += g->width;
912           gstring->rbearing += g->width;
913           g++;
914         }
915     }
916
917   if (box)
918     {
919       /* Insert the right side of the box.  */
920       int gidx = GLYPH_INDEX (g);
921       MGlyph box_glyph = g[-1];
922
923       box_glyph.type = GLYPH_BOX;
924       box_glyph.width
925         = (control->fixed_width
926            ? frame->space_width
927            : box->inner_hmargin + box->width + box->outer_hmargin);
928       box_glyph.lbearing = 0;
929       box_glyph.rbearing = box_glyph.width;
930       box_glyph.xoff = 0;
931       box_glyph.right_padding = 1;
932       gstring->width += box_glyph.width;
933       gstring->rbearing += box_glyph.width;
934       INSERT_GLYPH (gstring, gidx, box_glyph);
935     }
936
937   gstring->text_ascent = gstring->ascent;
938   gstring->text_descent = gstring->descent;
939   if (gstring->text_ascent < gstring->physical_ascent)
940     gstring->text_ascent = gstring->physical_ascent;
941   if (gstring->text_descent < gstring->physical_descent)
942     gstring->text_descent = gstring->physical_descent;
943   gstring->line_ascent = gstring->text_ascent;
944   gstring->line_descent = gstring->text_descent;
945   if (box_line_height > 0)
946     {
947       gstring->line_ascent += box_line_height;
948       gstring->physical_ascent = gstring->line_ascent;
949       gstring->line_descent += box_line_height;
950       gstring->physical_descent = gstring->line_descent;
951     }
952
953   if (gstring->line_ascent < control->min_line_ascent)
954     gstring->line_ascent = control->min_line_ascent;
955   else if (control->max_line_ascent
956            && control->max_line_ascent > control->min_line_ascent
957            && gstring->line_ascent > control->max_line_ascent)
958     gstring->line_ascent = control->max_line_ascent;
959
960   if (gstring->line_descent < control->min_line_descent)
961     gstring->line_descent = control->min_line_descent;
962   else if (control->max_line_descent
963            && control->max_line_descent > control->min_line_descent
964            && gstring->line_descent > control->max_line_descent)
965     gstring->line_descent = control->max_line_descent;
966   gstring->height = gstring->line_ascent + gstring->line_descent;
967
968   if (control->orientation_reversed
969       && tab_found)
970     {
971       /* We must adjust TAB width for RTL orientation.  */
972       width = gstring->indent;
973
974       for (g = MGLYPH (gstring->used - 2); g->type != GLYPH_ANCHOR; g--)
975         {
976           if (g->type == GLYPH_CHAR && g->c == '\t')
977             {
978               int this_width = tab_width - (width % tab_width);
979
980               if (g[1].type == GLYPH_PAD)
981                 this_width -= g[1].width;
982               if (g[-1].type == GLYPH_PAD)
983                 this_width -= g[-1].width;              
984               if (this_width < 2)
985                 this_width = 2;
986               gstring->width += this_width - g->width;
987               gstring->rbearing += this_width - g->width;
988               g->width = this_width;
989               width += this_width;
990             }
991           else
992             width += g->width;
993         }
994     }
995 }
996
997
998 static MDrawRegion
999 draw_background (MFrame *frame, MDrawWindow win, int x, int y,
1000                  MGlyphString *gstring, int from, int to,
1001                  int *from_idx, int *to_idx, int *to_x)
1002 {
1003   MGlyph *g = MGLYPH (1);
1004   MDrawRegion region = (MDrawRegion) NULL;
1005   MDrawControl *control = &gstring->control;
1006   int cursor_pos = -1;
1007   int prev_pos = -1;
1008   int cursor_bidi = control->cursor_bidi;
1009
1010   if (control->with_cursor && control->cursor_width)
1011     {
1012       if (gstring->from <= control->cursor_pos
1013           && gstring->to > control->cursor_pos)
1014         cursor_pos = control->cursor_pos;
1015       if (cursor_bidi
1016           && gstring->from <= control->cursor_pos - 1
1017           && gstring->to > control->cursor_pos - 1)
1018         prev_pos = control->cursor_pos - 1;
1019     }
1020
1021   *from_idx = *to_idx = 0;
1022   while (g->type != GLYPH_ANCHOR)
1023     {
1024       if (g->pos >= from && g->pos < to)
1025         {
1026           MGlyph *fromg = g, *cursor = NULL;
1027           MRealizedFace *rface = g->rface;
1028           int width = 0;
1029           int cursor_width = 0;
1030           int cursor_x;
1031
1032           if (! *from_idx)
1033             *from_idx = GLYPH_INDEX (g);
1034           while (g->pos >= from && g->pos < to
1035                  && g->rface == rface)
1036             {
1037               g->enabled = 1;
1038               if (g->type != GLYPH_BOX
1039                   && g->pos <= cursor_pos && g->to > cursor_pos)
1040                 {
1041                   if (! cursor)
1042                     cursor = g, cursor_x = x + width;
1043                   cursor_width += g->width;
1044                 }
1045               width += g++->width;
1046             }
1047           if (width > 0
1048               && (control->as_image
1049                   || rface->face.property[MFACE_VIDEOMODE] == Mreverse))
1050             {
1051               int this_x = x, this_width = width;
1052
1053               if (fromg->type == GLYPH_BOX)
1054                 this_x += fromg->width, this_width -= fromg->width;
1055               if (g[-1].type == GLYPH_BOX)
1056                 this_width -= g[-1].width;
1057               (frame->driver->fill_space)
1058                 (frame, win, rface, 0,
1059                  this_x, y - gstring->text_ascent, this_width,
1060                  gstring->text_ascent + gstring->text_descent,
1061                  control->clip_region);
1062             }
1063           if (cursor)
1064             {
1065               MDrawMetric rect;
1066             
1067               rect.x = cursor_x;
1068               rect.y = y - gstring->text_ascent;
1069               rect.height = gstring->text_ascent + gstring->text_descent;
1070               if (! cursor_bidi)
1071                 {
1072                   rect.width = ((control->cursor_width > 0
1073                                  && control->cursor_width < cursor_width)
1074                                 ? control->cursor_width : cursor_width);
1075                 }
1076               else
1077                 {
1078                   if (cursor->bidi_level % 2)
1079                     rect.x += cursor_width - 1;
1080                   rect.width = 1;
1081                 }
1082               (*frame->driver->fill_space)
1083                 (frame, win, rface, 1, rect.x, rect.y, rect.width, rect.height,
1084                  control->clip_region);
1085               if (! region)
1086                 region = (*frame->driver->region_from_rect) (&rect);
1087               else
1088                 (*frame->driver->region_add_rect) (region, &rect);
1089               if (cursor_bidi)
1090                 {
1091                   if (cursor->bidi_level % 2)
1092                     rect.x -= 3;
1093                   rect.height = 2;
1094                   rect.width = cursor_width < 4 ? cursor_width : 4;
1095                   (*frame->driver->fill_space)
1096                     (frame, win, rface, 1,
1097                      rect.x, rect.y, rect.width, rect.height,
1098                      control->clip_region);
1099                   (*frame->driver->region_add_rect) (region, &rect);
1100                 }
1101             }
1102
1103           if (prev_pos >= 0)
1104             {
1105               int temp_width = 0;
1106
1107               cursor_width = 0;
1108               cursor = NULL;
1109               while (fromg < g)
1110                 {
1111                   if (fromg->type != GLYPH_BOX
1112                       && fromg->pos <= prev_pos && fromg->to > prev_pos)
1113                     {
1114                       if (! cursor)
1115                         cursor = fromg, cursor_x = x + temp_width;
1116                       cursor_width += fromg->width;
1117                     }
1118                   temp_width += fromg++->width;
1119                 }
1120               if (cursor)
1121                 {
1122                   MDrawMetric rect;
1123
1124                   rect.x = cursor_x;
1125                   if (! (cursor->bidi_level % 2))
1126                     rect.x += cursor_width - 1;
1127                   rect.y = y - gstring->text_ascent;
1128                   rect.height = gstring->text_ascent + gstring->text_descent;
1129                   rect.width = 1;
1130                   (*frame->driver->fill_space)
1131                     (frame, win, rface, 1,
1132                      rect.x, rect.y, rect.width, rect.height,
1133                      control->clip_region);
1134                   if (! region)
1135                     region = (*frame->driver->region_from_rect) (&rect);
1136                   else
1137                     (*frame->driver->region_add_rect) (region, &rect);
1138                   rect.y += rect.height - 2;
1139                   rect.height = 2;
1140                   rect.width = cursor_width < 4 ? cursor_width : 4;
1141                   if (! (cursor->bidi_level % 2))
1142                     rect.x -= rect.width - 1;
1143                   (*frame->driver->fill_space) (frame, win, rface, 1,
1144                                     rect.x, rect.y, rect.width, rect.height,
1145                                     control->clip_region);
1146                   (*frame->driver->region_add_rect) (region, &rect);
1147                 }
1148             }
1149           x += width;
1150           *to_idx = GLYPH_INDEX (g);
1151           *to_x = x;
1152         }
1153       else
1154         g++->enabled = 0;
1155     }
1156   return region;
1157 }
1158
1159 static void
1160 render_glyphs (MFrame *frame, MDrawWindow win, int x, int y, int width,
1161                MGlyphString *gstring, int from_idx, int to_idx,
1162                int reverse, MDrawRegion region)
1163 {
1164   MGlyph *g = MGLYPH (from_idx), *gend = MGLYPH (to_idx);
1165
1166   if (region)
1167     {
1168       MDrawMetric rect;
1169
1170       (*frame->driver->region_to_rect) (region, &rect);
1171       if (rect.x > x)
1172         {
1173           while (g != gend && x + g->rbearing <= rect.x)
1174             {
1175               x += g->width;
1176               width -= g++->width;
1177               while (! g->enabled && g != gend)
1178                 g++;
1179             }
1180         }
1181       rect.x += rect.width;
1182       if (rect.x < x + width)
1183         {
1184           while (g != gend
1185                  && (x + width - gend[-1].width + gend[-1].lbearing >= rect.x))
1186             {
1187               width -= (--gend)->width;
1188               while (! gend->enabled && g != gend)
1189                 gend--;
1190             }
1191           if (g != gend)
1192             while (gend[-1].to == gend->to) gend++;
1193         }
1194     }
1195
1196   while (g != gend)
1197     {
1198       if (g->enabled)
1199         {
1200           MRealizedFace *rface = g->rface;
1201           int width = g->width;
1202           MGlyph *from_g = g++;
1203
1204           /* Handle the glyphs of the same type/face at once.  */
1205           while (g != gend
1206                  && g->type == from_g->type
1207                  && g->rface == rface
1208                  && (g->code < 0) == (from_g->code < 0)
1209                  && g->enabled)
1210             width += g++->width;
1211
1212           if (from_g->type == GLYPH_CHAR)
1213             {
1214               if (rface->rfont && from_g->code != MCHAR_INVALID_CODE)
1215                 (rface->rfont->driver->render) (win, x, y, gstring, from_g, g,
1216                                                 reverse, region);
1217               else
1218                 (*frame->driver->draw_empty_boxes) (win, x, y, gstring, from_g, g,
1219                                         reverse, region);
1220             }
1221           else if (from_g->type == GLYPH_BOX)
1222             {
1223               /* Draw the left or right side of a box.  If
1224                  from_g->lbearing is nonzero, this is the left side,
1225                  else this is the right side.  */
1226               (*frame->driver->draw_box) (frame, win, gstring, from_g, x, y, 0, region);
1227             }
1228
1229           if (from_g->type != GLYPH_BOX)
1230             {
1231               if (rface->hline)
1232                 (*frame->driver->draw_hline) (frame, win, gstring, rface, reverse,
1233                                   x, y, width, region);
1234               if (rface->box
1235                   && ! reverse)
1236                 /* Draw the top and bottom side of a box.  */
1237                 (*frame->driver->draw_box) (frame, win, gstring, from_g,
1238                                    x, y, width, region);
1239             }
1240           x += width;
1241         }
1242       else
1243         g++;
1244     }
1245 }
1246
1247
1248 static int
1249 find_overlapping_glyphs (MGlyphString *gstring, int *left, int *right,
1250                          int *from_x, int *to_x)
1251 {
1252   MGlyph *g;
1253   int left_idx = *left, right_idx = *right;
1254   int left_x, right_x, x;
1255
1256   for (g = MGLYPH (*left) - 1, x = 0; g->type != GLYPH_ANCHOR; g--)
1257     {
1258       x -= g->width;
1259       if (x + g->rbearing > 0)
1260         {
1261           while (g[-1].pos == g->pos && g[-1].type != GLYPH_ANCHOR)
1262             x -= (--g)->width;
1263           left_idx = GLYPH_INDEX (g);
1264           left_x = x;
1265         }
1266     }
1267
1268   for (g = MGLYPH (*right), x = 0; g->type != GLYPH_ANCHOR; g++)
1269     {
1270       x += g->width;
1271       if (x - g->width + g->lbearing < 0)
1272         {
1273           while (g->pos == g[1].pos && g[1].type != GLYPH_ANCHOR)
1274             x += (++g)->width;
1275           right_idx = GLYPH_INDEX (g) + 1;
1276           right_x = x;
1277         }
1278     }
1279
1280   if (*left == left_idx && *right == right_idx)
1281     return 0;
1282
1283   if (*left != left_idx)
1284     {
1285       for (g = MGLYPH (*left) - 1; GLYPH_INDEX (g) >= left_idx; g--)
1286         g->enabled = 1;
1287       *left = left_idx;
1288       *from_x += left_x;
1289     }
1290   if (*right != right_idx)
1291     {
1292       for (g = MGLYPH (*right); GLYPH_INDEX (g) < right_idx; g++)
1293         g->enabled = 1;
1294       *right = right_idx;
1295       *to_x += right_x;
1296     }
1297   return 1;
1298 }
1299
1300
1301 static int
1302 gstring_width (MGlyphString *gstring, int from, int to, int *rbearing)
1303 {
1304   MGlyph *g;
1305   int width;
1306
1307   if (from <= gstring->from && to >= gstring->to)
1308     {
1309       if (rbearing)
1310         *rbearing = gstring->rbearing;
1311       return gstring->width;
1312     }
1313
1314   if (rbearing)
1315     *rbearing = 0;
1316   for (g = MGLYPH (1), width = 0; g->type != GLYPH_ANCHOR; g++)
1317     if (g->pos >= from && g->pos < to)
1318       {
1319         if (rbearing && width + g->rbearing > *rbearing)
1320           *rbearing = width + g->rbearing;
1321         width += g->width;
1322       }
1323   return width;
1324 }
1325
1326
1327 static void
1328 render_glyph_string (MFrame *frame, MDrawWindow win, int x, int y,
1329                      MGlyphString *gstring, int from, int to)
1330 {
1331   MDrawControl *control = &gstring->control;
1332   MDrawMetric rect;
1333   MDrawRegion clip_region, cursor_region;
1334   int from_idx, to_idx;
1335   int to_x;
1336
1337   if (control->orientation_reversed)
1338     x -= gstring->indent + gstring_width (gstring, from, to, NULL);
1339   else
1340     x += gstring->indent;
1341
1342   /* At first, draw all glyphs without cursor.  */
1343   cursor_region = draw_background (frame, win, x, y, gstring, from, to,
1344                                    &from_idx, &to_idx, &to_x);
1345
1346   if (control->partial_update)
1347     {
1348       rect.x = x;
1349       rect.width = to_x - x;
1350       if (find_overlapping_glyphs (gstring, &from_idx, &to_idx, &x, &to_x))
1351         {
1352           rect.y = y - gstring->line_ascent;
1353           rect.height = gstring->height;
1354           clip_region = (*frame->driver->region_from_rect) (&rect);
1355           if (control->clip_region)
1356             (*frame->driver->intersect_region) (clip_region, control->clip_region);
1357         }
1358       else
1359         clip_region = control->clip_region;
1360     }
1361   else
1362     clip_region = control->clip_region;
1363
1364   render_glyphs (frame, win, x, y, to_x - x, gstring, from_idx, to_idx,
1365                  0, clip_region);
1366   if (cursor_region)
1367     {
1368       if (clip_region)
1369         (*frame->driver->intersect_region) (cursor_region, clip_region);
1370       render_glyphs (frame, win, x, y, to_x - x, gstring, from_idx, to_idx,
1371                      1, cursor_region);
1372     }
1373   if (clip_region != control->clip_region)
1374     (*frame->driver->free_region) (clip_region);
1375   if (cursor_region)
1376     (*frame->driver->free_region) (cursor_region);
1377   return;
1378 }
1379
1380 static int gstring_num;
1381
1382 static void
1383 free_gstring (void *object)
1384 {
1385   MGlyphString *gstring = (MGlyphString *) object;
1386
1387   if (gstring->next)
1388     free_gstring (gstring->next);
1389   if (gstring->size > 0)
1390     free (gstring->glyphs);
1391   free (gstring);
1392   gstring_num--;
1393 }
1394
1395
1396 static MGlyphString scratch_gstring;
1397
1398 static MGlyphString *
1399 alloc_gstring (MFrame *frame, MText *mt, int pos, MDrawControl *control,
1400                int line, int y)
1401 {
1402   MGlyphString *gstring;
1403
1404   if (pos == mt->nchars)
1405     {
1406       gstring = &scratch_gstring;
1407     }
1408   else
1409     {
1410       M17N_OBJECT (gstring, free_gstring, MERROR_DRAW);
1411       MLIST_INIT1 (gstring, glyphs, 128);
1412       gstring_num++;
1413     }
1414
1415   gstring->frame = frame;
1416   gstring->tick = frame->tick;
1417   gstring->top = gstring;
1418   gstring->mt = mt;
1419   gstring->control = *control;
1420   gstring->indent = gstring->width_limit = 0;
1421   if (control->format)
1422     (*control->format) (line, y, &(gstring->indent), &(gstring->width_limit));
1423   else
1424     gstring->width_limit = control->max_line_width;
1425   gstring->anti_alias = control->anti_alias;
1426   return gstring;
1427 }
1428
1429 /* Truncate the line width of GSTRING to GSTRING->width_limit.  */
1430
1431 static void
1432 truncate_gstring (MFrame *frame, MText *mt, MGlyphString *gstring)
1433 {
1434   int width;
1435   int i;
1436   int *pos_width;
1437   MGlyph *g;
1438   int pos;
1439
1440   /* Setup the array POS_WIDTH so that POS_WIDTH[I - GSTRING->from] is
1441      a width of glyphs for the character at I of GSTRING->mt.  If I is
1442      not a beginning of a grapheme cluster, the corresponding element
1443      is 0.  */
1444   MTABLE_ALLOCA (pos_width, gstring->to - gstring->from, MERROR_DRAW);
1445   memset (pos_width, 0, sizeof (int) * (gstring->to - gstring->from));
1446   for (g = MGLYPH (1); g->type != GLYPH_ANCHOR; g++)
1447     pos_width[g->pos - gstring->from] += g->width;
1448   for (i = 0, width = 0; i < gstring->to - gstring->from; i++)
1449     {
1450       if (pos_width[i] > 0)
1451         {
1452           if (width + pos_width[i] > gstring->width_limit)
1453             break;
1454         }
1455       width += pos_width[i];
1456     }
1457
1458   pos = gstring->from + i;
1459   if (gstring->control.line_break)
1460     {
1461       pos = (*gstring->control.line_break) (gstring->mt, gstring->from + i,
1462                                             gstring->from, gstring->to, 0, 0);
1463       if (pos <= gstring->from || pos >= gstring->to)
1464         return;
1465     }
1466   compose_glyph_string (frame, mt, gstring->from, pos, gstring);
1467   layout_glyph_string (frame, gstring);
1468 }
1469
1470
1471 /* Return a gstring that covers a character at POS.  */
1472
1473 static MGlyphString *
1474 get_gstring (MFrame *frame, MText *mt, int pos, int to, MDrawControl *control)
1475 {
1476   MGlyphString *gstring = NULL;
1477
1478   if (pos < mtext_nchars (mt))
1479     {
1480       MTextProperty *prop = mtext_get_property (mt, pos, M_glyph_string);
1481
1482       if (prop
1483           && ((prop->start != 0
1484                && mtext_ref_char (mt, prop->start - 1) != '\n')
1485               || (prop->end < mtext_nchars (mt)
1486                   && mtext_ref_char (mt, prop->end - 1) != '\n')))
1487         {
1488           mtext_detach_property (prop);
1489           prop = NULL;
1490         }
1491       if (prop)
1492         {
1493           gstring = prop->val;
1494           if (gstring->frame != frame
1495               || gstring->tick != frame->tick
1496               || memcmp (control, &gstring->control,
1497                          (char *) (&control->with_cursor)
1498                          - (char *) (control)))
1499             {
1500               mtext_detach_property (prop);
1501               gstring = NULL;
1502             }
1503         }
1504     }
1505   else if (! control->cursor_width)
1506     return NULL;
1507
1508   if (gstring)
1509     {
1510       MGlyphString *gst;
1511       int offset;
1512
1513       offset = mtext_character (mt, pos, 0, '\n');
1514       if (offset < 0)
1515         offset = 0;
1516       else
1517         offset++;
1518       offset -= gstring->from;
1519       if (offset)
1520         for (gst = gstring; gst; gst = gst->next)
1521           {
1522             int i;
1523
1524             gst->from += offset;
1525             gst->to += offset;
1526             for (i = 0; i < gst->used; i++)
1527               {
1528                 gst->glyphs[i].pos += offset;
1529                 gst->glyphs[i].to += offset;
1530               }
1531           }
1532       M17N_OBJECT_REF (gstring);
1533     }
1534   else
1535     {
1536       int beg, end;
1537       int line = 0, y = 0;
1538
1539       if (control->two_dimensional)
1540         {
1541           beg = mtext_character (mt, pos, 0, '\n');
1542           if (beg < 0)
1543             beg = 0;
1544           else
1545             beg++;
1546           end = mtext_nchars (mt) + (control->cursor_width != 0);
1547         }
1548       else
1549         {
1550           beg = pos;
1551           end = to;
1552         }
1553       gstring = alloc_gstring (frame, mt, beg, control, line, y);
1554       compose_glyph_string (frame, mt, beg, end, gstring);
1555       layout_glyph_string (frame, gstring);
1556       end = gstring->to;
1557       if (control->two_dimensional
1558           && gstring->width_limit
1559           && gstring->width > gstring->width_limit)
1560         {
1561           MGlyphString *gst = gstring;
1562
1563           truncate_gstring (frame, mt, gst);
1564           while (gst->to < end)
1565             {
1566               line++, y += gst->height;
1567               gst->next = alloc_gstring (frame, mt, gst->from, control,
1568                                          line, y);
1569               gst->next->top = gstring;
1570               compose_glyph_string (frame, mt, gst->to, end, gst->next);
1571               gst = gst->next;
1572               layout_glyph_string (frame, gst);
1573               if (gst->width <= gst->width_limit)
1574                 break;
1575               truncate_gstring (frame, mt, gst);
1576             }
1577         }
1578
1579       if (! control->disable_caching && pos < mtext_nchars (mt))
1580         {
1581           MTextProperty *prop = mtext_property (M_glyph_string, gstring,
1582                                                 MTEXTPROP_VOLATILE_STRONG);
1583
1584           if (end > mtext_nchars (mt))
1585             end = mtext_nchars (mt);
1586           mtext_attach_property (mt, beg, end, prop);
1587           M17N_OBJECT_UNREF (prop);
1588         }
1589     }
1590
1591   while (gstring->to <= pos)
1592     {
1593       if (! gstring->next)
1594         mdebug_hook ();
1595       gstring = gstring->next;
1596     }
1597   gstring->control = *control;
1598
1599   return gstring;
1600 }
1601
1602
1603 static MDrawControl control_noop;
1604
1605 #define ASSURE_CONTROL(control) \
1606   if (! control)                \
1607     control = &control_noop;    \
1608   else
1609
1610
1611 static int
1612 draw_text (MFrame *frame, MDrawWindow win, int x, int y,
1613            MText *mt, int from, int to,
1614            MDrawControl *control)
1615 {
1616   MGlyphString *gstring;
1617
1618   M_CHECK_POS_X (mt, from, -1);
1619   ASSURE_CONTROL (control);
1620   if (to > mtext_nchars (mt) + (control->cursor_width != 0))
1621     to = mtext_nchars (mt) + (control->cursor_width != 0);
1622   else if (to < from)
1623     to = from;
1624
1625   gstring = get_gstring (frame, mt, from, to, control);
1626   if (! gstring)
1627     MERROR (MERROR_DRAW, -1);
1628   render_glyph_string (frame, win, x, y, gstring, from, to);
1629   from = gstring->to;
1630   while (from < to)
1631     {
1632       y += gstring->line_descent;
1633       M17N_OBJECT_UNREF (gstring->top);
1634       gstring = get_gstring (frame, mt, from, to, control);
1635       y += gstring->line_ascent;
1636       render_glyph_string (frame, win, x, y, gstring, from, to);
1637       from = gstring->to;
1638     }
1639   M17N_OBJECT_UNREF (gstring->top);
1640
1641   return 0;
1642 }
1643
1644
1645 static MGlyph *
1646 find_glyph_in_gstring (MGlyphString *gstring, int pos, int forwardp)
1647 {
1648   MGlyph *g;
1649
1650   if (forwardp)
1651     {
1652       for (g = MGLYPH (1); g->type != GLYPH_ANCHOR; g++)
1653         if (g->pos <= pos && g->to > pos)
1654           break;
1655     }
1656   else
1657     {
1658       for (g = MGLYPH (gstring->used - 2); g->type != GLYPH_ANCHOR; g--)
1659         if (g->pos <= pos && g->to > pos)
1660           break;
1661     }
1662   return g;
1663 }
1664
1665 \f
1666 /* for debugging... */
1667 char work[16];
1668
1669 char *
1670 dump_combining_code (int code)
1671 {
1672   char *vallign = "tcbB";
1673   char *hallign = "lcr";
1674   char *p;
1675   int off_x, off_y;
1676
1677   if (! code)
1678     return "none";
1679   if (COMBINING_BY_CLASS_P (code))
1680     code = combining_code_from_class (COMBINING_CODE_CLASS (code));
1681   work[0] = vallign[COMBINING_CODE_BASE_Y (code)];
1682   work[1] = hallign[COMBINING_CODE_BASE_X (code)];
1683   off_y = COMBINING_CODE_OFF_Y (code) - 128;
1684   off_x = COMBINING_CODE_OFF_X (code) - 128;
1685   if (off_y > 0)
1686     sprintf (work + 2, "+%d", off_y);
1687   else if (off_y < 0)
1688     sprintf (work + 2, "%d", off_y);
1689   else if (off_x == 0)
1690     sprintf (work + 2, ".");
1691   p = work + strlen (work);
1692   if (off_x > 0)
1693     sprintf (p, ">%d", off_x);
1694   else if (off_x < 0)
1695     sprintf (p, "<%d", -off_x);
1696   p += strlen (p);
1697   p[0] = vallign[COMBINING_CODE_ADD_Y (code)];
1698   p[1] = hallign[COMBINING_CODE_ADD_X (code)];
1699   p[2] = '\0';
1700   return work;
1701 }
1702
1703 void
1704 dump_gstring (MGlyphString *gstring, int indent)
1705 {
1706   char *prefix = (char *) alloca (indent + 1);
1707   MGlyph *g, *last_g = gstring->glyphs + gstring->used;
1708
1709   memset (prefix, 32, indent);
1710   prefix[indent] = 0;
1711
1712   fprintf (stderr, "(glyph-string");
1713
1714   for (g = MGLYPH (0); g < last_g; g++)
1715     fprintf (stderr,
1716              "\n%s  (%02d %s pos:%d-%d c:%04X code:%04X face:%x cmb:%s w:%02d bidi:%d)",
1717              prefix,
1718              g - gstring->glyphs,
1719              (g->type == GLYPH_SPACE ? "SPC": g->type == GLYPH_PAD ? "PAD"
1720               : g->type == GLYPH_ANCHOR ? "ANC"
1721               : g->type == GLYPH_BOX ? "BOX" : "CHR"),
1722              g->pos, g->to, g->c, g->code, (unsigned) g->rface,
1723              dump_combining_code (g->combining_code),
1724              g->width, g->bidi_level);
1725   fprintf (stderr, ")");
1726 }
1727 \f
1728
1729 /* m17n-X internal APIs */
1730
1731 int
1732 mdraw__init ()
1733 {
1734   M_glyph_string = msymbol_as_managing_key ("  glyph-string");
1735
1736   memset (&scratch_gstring, 0, sizeof (scratch_gstring));
1737   MLIST_INIT1 (&scratch_gstring, glyphs, 3);
1738
1739   Mlatin = msymbol ("latin");
1740   Minherited = msymbol ("inherited");
1741
1742   McatCc = msymbol ("Cc");
1743   McatCf = msymbol ("Cf");
1744
1745   MbidiR = msymbol ("R");
1746   MbidiAL = msymbol ("AL");
1747   MbidiRLE = msymbol ("RLE");
1748   MbidiRLO = msymbol ("RLO");
1749   MbidiBN = msymbol ("BN");
1750   MbidiS = msymbol ("S");
1751 #ifdef HAVE_FRIBIDI
1752   fribidi_set_mirroring (TRUE);
1753 #endif
1754
1755   return 0;
1756 }
1757
1758 void
1759 mdraw__fini ()
1760 {
1761   MLIST_FREE1 (&scratch_gstring, glyphs);
1762 }
1763
1764 /*** @} */
1765 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
1766
1767 \f
1768 /* External API */
1769 /*** @addtogroup m17nDraw */
1770 /*** @{ */
1771
1772 /*=*/
1773 /***en
1774     @brief Draw an M-text on a window.
1775
1776     The mdraw_text () function draws the text between $FROM and $TO of
1777     M-text $MT on window $WIN of frame $FRAME at coordinate ($X, $Y).
1778
1779     The appearance of the text (size, style, color, etc) is specified
1780     by the value of the text property whose key is @c Mface.  If the
1781     M-text or a part of the M-text does not have such a text property,
1782     the default face of $FRAME is used.
1783
1784     The font used to draw a character in the M-text is selected from
1785     the value of the fontset property of a face by the following
1786     algorithm:
1787
1788     <ol>
1789
1790     <li> Search the text properties given to the character for the one
1791          whose key is @c Mcharset; its value should be either a symbol
1792          specifying a charset or #Mnil.  If the value is #Mnil,
1793          proceed to the next step.
1794
1795          Otherwise, search the mapping table of the fontset for the
1796          charset.  If no entry is found proceed to the next step.  
1797
1798          If an entry is found, use one of the fonts in the entry that
1799          has a glyph for the character and that matches best with the
1800          face properties.  If no such font exists, proceed to the next
1801          step.
1802
1803     <li> Get the character property "script" of the character.  If it is
1804          inherited, get the script property from the previous
1805          characters.  If there is no previous character, or none of
1806          them has the script property other than inherited, proceed to
1807          the next step.
1808
1809          Search the text properties given to the character for the one
1810          whose key is @c Mlanguage; its value should be either a
1811          symbol specifying a language or @c Mnil.
1812
1813          Search the mapping table of the fontset for the combination
1814          of the script and language.  If no entry is found, proceed to
1815          the next step.  
1816
1817         If an entry is found, use one of the fonts in the entry that
1818          has a glyph for the character and that matches best with the
1819          face properties.  If no such font exists, proceed to the next
1820          step.
1821
1822     <li> Search the fall-back table of the fontset for a font that has
1823          a glyph of the character.  If such a font is found, use that
1824          font.
1825
1826     </ol>
1827
1828     If no font is found by the algorithm above, this function draws an
1829     empty box for the character.
1830
1831     This function draws only the glyph foreground.  To specify the
1832     background color, use mdraw_image_text () or
1833     mdraw_text_with_control ().
1834
1835     This function is the counterpart of <tt>XDrawString ()</tt>,
1836     <tt>XmbDrawString ()</tt>, and <tt>XwcDrawString ()</tt> functions
1837     in the X Window System.
1838
1839     @return
1840     If the operation was successful, mdraw_text () returns 0.  If an
1841     error is detected, it returns -1 and assigns an error code to the
1842     external variable #merror_code.  */
1843 /***ja
1844     @brief ¥¦¥£¥ó¥É¥¦¤Ë M-text ¤òÉÁ²è¤¹¤ë.
1845
1846     ´Ø¿ô mdraw_text () ¤Ï¡¢¥Õ¥ì¡¼¥à $FRAME ¤Î¥¦¥£¥ó¥É¥¦ $WIN ¤ÎºÂɸ 
1847     ($X, $Y) ¤Ë¡¢M-text $MT ¤Î $FROM ¤«¤é $TO ¤Þ¤Ç¤Î¥Æ¥­¥¹¥È¤ò
1848     ÉÁ²è¤¹¤ë¡£
1849
1850     ¥Æ¥­¥¹¥È¤Î¸«±É¤¨¡Ê¥Õ¥©¥ó¥È¡¢¥¹¥¿¥¤¥ë¡¢¿§¤Ê¤É¡Ë¤Ï¡¢¥­¡¼¤¬ @c Mface 
1851     ¤Ç¤¢¤ë¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤ÎÃͤˤè¤Ã¤Æ·è¤Þ¤ë¡£M-text ¤Î°ìÉô¤¢¤ë¤¤¤Ï
1852     Á´Éô¤Ë¤½¤Î¤è¤¦¤Ê¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤¬ÉÕ¤¤¤Æ¤¤¤Ê¤¤¾ì¹ç¤Ë¤Ï¡¢$FRAME 
1853     ¤Î¥Ç¥Õ¥©¥ë¥È¥Õ¥§¡¼¥¹¤¬ÍѤ¤¤é¤ì¤ë¡£
1854
1855     M-text ¤Î³Æʸ»ú¤òɽ¼¨¤¹¤ë¥Õ¥©¥ó¥È¤Ï¡¢¥Õ¥§¡¼¥¹¤Î fontset ¥×¥í¥Ñ¥Æ¥£
1856     ¤ÎÃͤ«¤é°Ê²¼¤Î¥¢¥ë¥´¥ê¥º¥à¤ÇÁª¤Ð¤ì¤ë¡£
1857
1858     <ol>
1859
1860     <li> ¤½¤Îʸ»ú¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Î¤¦¤Á¡¢¥­¡¼¤¬ @c Mcharset ¤Ç¤¢¤ë
1861          ¤â¤Î¤ÎÃͤòÄ´¤Ù¤ë¡£¤³¤ÎÃͤÏʸ»ú¥»¥Ã¥È¤òɽ¤ï¤¹¥·¥ó¥Ü¥ë¤« #Mnil 
1862          ¤Î¤É¤Á¤é¤«¤Ç¤¢¤ë¡£#Mnil ¤Ê¤é¤Ð¡¢¼¡¤Î¥¹¥Æ¥Ã¥×¤Ë¿Ê¤à¡£¤½¤¦¤Ç¤Ê
1863          ¤±¤ì¤Ð¡¢¤½¤Î¥Õ¥©¥ó¥È¥»¥Ã¥È¤Î¥Þ¥Ã¥Ô¥ó¥°¥Æ¡¼¥Ö¥ë¤«¤é¤½¤Îʸ»ú¥»¥Ã
1864          ¥ÈÍѤΤâ¤Î¤òõ¤¹¡£¥Õ¥©¥ó¥È¤¬¤ß¤Ä¤«¤é¤Ê¤±¤ì¤Ð¡¢¼¡¤Î¥¹¥Æ¥Ã¥×¤Ë
1865          ¿Ê¤à¡£
1866          
1867          ¤½¤Îʸ»ú¥»¥Ã¥ÈÍѤΥե©¥ó¥È¤¬¤ß¤Ä¤«¤ì¤Ð¡¢¤½¤ì¤é¤Î¤¦¤Á¸½ºß¤Îʸ
1868          »úÍѤΥ°¥ê¥Õ¤ò»ý¤Á¡¢¥Õ¥§¡¼¥¹¤Î³Æ¥×¥í¥Ñ¥Æ¥£¤ËºÇ¤â¤è¤¯¹çÃפ·¤Æ
1869          ¤¤¤ë¤â¤Î¤ò»È¤¦¡£¤½¤Î¤è¤¦¤Ê¥Õ¥©¥ó¥È¤¬Ìµ¤±¤ì¤Ð¼¡¤Î¥¹¥Æ¥Ã¥×¤Ë¿Ê
1870          ¤à¡£
1871
1872     <li> ¤½¤Îʸ»ú¤Îʸ»ú¥×¥í¥Ñ¥Æ¥£ "script" ¡Ê¥¹¥¯¥ê¥×¥È¡Ë¤òÄ´¤Ù¤ë¡£·Ñ
1873          ¾µ¤µ¤ì¤Æ¤¤¤ë¤Ê¤é¤Ð¤½¤ì°ÊÁ°¤Îʸ»ú¤Îʸ»ú¥×¥í¥Ñ¥Æ¥£ "script" ¤ò
1874          Ä´¤Ù¤ë¡£Á°¤Îʸ»ú¤¬¤Ê¤«¤Ã¤¿¤ê¡¢¤½¤Îʸ»ú¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Ã¤Æ¤¤¤Ê
1875          ¤«¤Ã¤¿¾ì¹ç¤Ë¤Ï¡¢¼¡¤Î¥¹¥Æ¥Ã¥×¤Ë¿Ê¤à¡£
1876
1877          ¤½¤Îʸ»ú¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Î¤¦¤Á¡¢¥­¡¼¤¬ @c Mlanguage ¤Ç¤¢
1878          ¤ë¤â¤Î¤ÎÃͤòÄ´¤Ù¤ë¡£¤³¤ÎÃͤϸÀ¸ì¤òɽ¤ï¤¹¥·¥ó¥Ü¥ë¤« @c Mnil ¤Î
1879          ¤¤¤º¤ì¤«¤Ç¤¢¤ë¡£
1880
1881          ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢¤½¤Î¸À¸ì¤È¥¹¥¯¥ê¥×¥È¤ÎÁȤ߹ç¤ï¤»ÍѤΥե©¥ó¥È
1882          ¥»¥Ã¥È¤ò¥Þ¥Ã¥Ô¥ó¥°¥Æ¡¼¥Ö¥ë¤«¤éõ¤¹¡£¸«¤Ä¤«¤é¤Ê¤±¤ì¤Ð¼¡¤Î¥¹¥Æ¥Ã
1883          ¥×¤Ë¿Ê¤à¡£
1884
1885          ¤½¤Î¤è¤¦¤Êʸ»ú¥»¥Ã¥ÈÍѤΥե©¥ó¥È¤¬¤ß¤Ä¤«¤ì¤Ð¡¢¤½¤ì¤é¤Î¤¦¤Á¸½
1886          ºß¤Îʸ»úÍѤΥ°¥ê¥Õ¤ò»ý¤Á¡¢¥Õ¥§¡¼¥¹¤Î³Æ¥×¥í¥Ñ¥Æ¥£¤ËºÇ¤â¤è¤¯¹ç
1887          Ãפ·¤Æ¤¤¤ë¤â¤Î¤ò»È¤¦¡£¤½¤Î¤è¤¦¤Ê¥Õ¥©¥ó¥È¤¬Ìµ¤±¤ì¤Ð¼¡¤Î¥¹¥Æ¥Ã
1888          ¥×¤Ë¿Ê¤à¡£
1889
1890     <li> ¤½¤Îʸ»ú¤Î¥°¥ê¥Õ¤ò»ý¤Ä¥Õ¥©¥ó¥È¤ò¡¢¥Õ¥©¥ó¥È¥»¥Ã¥È¤Îfall-back¥Æ¡¼
1891          ¥Ö¥ë¤«¤éõ¤¹¡£¥Õ¥©¥ó¥È¤¬¸«¤Ä¤«¤ì¤Ð¤½¤ì¤ò»È¤¦¡£
1892
1893     </ol>
1894
1895     °Ê¾å¤Î¥¢¥ë¥´¥ê¥º¥à¤Ç¥Õ¥©¥ó¥È¤¬¸«¤Ä¤«¤é¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï¤½¤Îʸ»ú
1896     ¤È¤·¤Æ¶õ¤Î»Í³Ñ·Á¤òɽ¼¨¤¹¤ë¡£
1897
1898     ¤³¤Î´Ø¿ô¤¬ÉÁ²è¤¹¤ë¤Î¤Ï¥°¥ê¥Õ¤ÎÁ°·Ê¤À¤±¤Ç¤¢¤ë¡£ÇØ·Ê¿§¤ò»ØÄꤹ¤ë¤Ë¤Ï¡¢
1899     ´Ø¿ô mdraw_image_text () ¤«´Ø¿ô mdraw_text_with_control () ¤ò»È¤¦
1900     ¤³¤È¡£
1901
1902     ¤³¤Î´Ø¿ô¤Ï¡¢X ¥¦¥£¥ó¥É¥¦¤Ë¤ª¤±¤ë´Ø¿ô <tt>XDrawString ()</tt>,
1903     <tt>XmbDrawString ()</tt>, <tt>XwcDrawString ()</tt> ¤ËÁêÅö¤¹¤ë¡£
1904
1905     @return
1906     ½èÍý¤¬À®¸ù¤·¤¿¾ì¹ç¡¢mdraw_text () ¤Ï 0 ÊÖ¤¹¡£¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì¤¿¾ì
1907     ¹ç¤Ï -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
1908
1909     @latexonly \IPAlabel{mdraw_text} @endlatexonly  */
1910
1911 /***
1912     @errors
1913     @c MERROR_RANGE
1914
1915     @seealso
1916     mdraw_image_text ()  */
1917
1918 int
1919 mdraw_text (MFrame *frame, MDrawWindow win, int x, int y,
1920             MText *mt, int from, int to)
1921 {
1922   MDrawControl control;
1923
1924   M_CHECK_WRITABLE (frame, MERROR_DRAW, -1);
1925   memset (&control, 0, sizeof control);
1926   control.as_image = 0;
1927   return draw_text (frame, win, x, y, mt, from, to, &control);
1928 }
1929
1930 /*=*/
1931
1932
1933 /***en
1934     @brief Draw an M-text on a window as an image.
1935
1936     The mdraw_image_text () function draws the text between $FROM and
1937     $TO of M-text $MT as image on window $WIN of frame $FRAME at
1938     coordinate ($X, $Y).
1939
1940     The way to draw a text is the same as in mdraw_text () except that
1941     this function also draws the background with the color specified
1942     by faces.
1943
1944     This function is the counterpart of <tt>XDrawImageString ()</tt>,
1945     <tt>XmbDrawImageString ()</tt>, and <tt>XwcDrawImageString ()</tt>
1946     functions in the X Window System.
1947
1948     @return
1949     If the operation was successful, mdraw_image_text () returns 0.
1950     If an error is detected, it returns -1 and assigns an error code
1951     to the external variable #merror_code.  */
1952
1953 /***ja
1954     @brief ¥Ç¥£¥¹¥×¥ì¥¤¤ËM-text ¤ò²èÁü¤È¤·¤ÆÉÁ¤¯.
1955   
1956     ´Ø¿ô mdraw_image_text () ¤Ï¡¢¥Õ¥ì¡¼¥à $FRAME ¤Î¥¦¥£¥ó¥É¥¦ $WIN ¤Î
1957     ºÂɸ ($X, $Y) ¤Ë¡¢M-text $MT ¤Î $FROM ¤«¤é $TO ¤Þ¤Ç¤Î¥Æ¥­¥¹¥È¤ò²è
1958     Áü¤È¤·¤ÆÉÁ¤¯¡£
1959
1960     ¥Æ¥­¥¹¥È¤ÎÉÁ²èÊýË¡¤Ï mdraw_text () ¤È¤Û¤ÜƱ¤¸¤Ç¤¢¤ë¤¬¡¢¤³¤Î´Ø¿ô¤Ç
1961     ¤Ï¥Õ¥§¡¼¥¹¤Ç»ØÄꤵ¤ì¤¿¿§¤ÇÇطʤâÉÁ¤¯ÅÀ¤¬°Û¤Ê¤Ã¤Æ¤¤¤ë¡£
1962
1963     ¤³¤Î´Ø¿ô¤Ï¡¢X ¥¦¥£¥ó¥É¥¦¤Ë¤ª¤±¤ë <tt>XDrawImageString ()</tt>,
1964     <tt>XmbDrawImageString ()</tt>, <tt>XwcDrawImageString ()</tt> ¤Ë
1965     ÁêÅö¤¹¤ë¡£
1966
1967     @return
1968     ½èÍý¤¬À®¸ù¤·¤¿¾ì¹ç¡¢mdraw_image_text () ¤Ï 0 ¤òÊÖ¤¹¡£¥¨¥é¡¼¤¬¸¡½Ð
1969     ¤µ¤ì¤¿¾ì¹ç¤Ï -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #m_errro ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ
1970     ¤ë¡£
1971
1972     @latexonly \IPAlabel{mdraw_image_text} @endlatexonly   */
1973
1974 /***
1975     @errors
1976     @c MERROR_RANGE
1977
1978     @seealso
1979     mdraw_text ()  */
1980
1981 int
1982 mdraw_image_text (MFrame *frame, MDrawWindow win, int x, int y,
1983                   MText *mt, int from, int to)
1984 {
1985   MDrawControl control;
1986
1987   M_CHECK_WRITABLE (frame, MERROR_DRAW, -1);
1988   memset (&control, 0, sizeof control);
1989   control.as_image = 1;
1990   return draw_text (frame, win, x, y, mt, from, to, &control);
1991 }
1992
1993 /*=*/
1994
1995 /***en
1996     @brief Draw an M-text on a window with fine control.
1997
1998     The mdraw_text_with_control () function draws the text between
1999     $FROM and $TO of M-text $MT on windows $WIN of frame $FRAME at
2000     coordinate ($X, $Y).
2001
2002     The way to draw a text is the same as in mdraw_text () except that
2003     this function also follows what specified in the drawing control
2004     object $CONTROL.
2005
2006     For instance, if <two_dimensional> of $CONTROL is nonzero, this
2007     function draw an M-text 2-dimensionally, i.e., newlines in M-text
2008     breaks lines and the following characters are drawn in the next
2009     line.  See the documentation of the structure @ MDrawControl for
2010     more detail.  */
2011
2012 /***ja
2013     @brief ¥Ç¥£¥¹¥×¥ì¥¤¤ËM-text ¤òÉÁ¤¯¡Ê¾ÜºÙ¤ÊÀ©¸æ¤Ä¤­¡Ë.
2014
2015     ´Ø¿ô mdraw_text_with_control () ¤Ï¡¢¥Õ¥ì¡¼¥à $FRAME ¤Î¥¦¥£¥ó¥É¥¦ 
2016     $WIN ¤ÎºÂɸ ($X, $Y) ¤Ë¡¢M-text $MT ¤Î $FROM ¤«¤é $TO ¤Þ¤Ç¤Î¥Æ¥­¥¹
2017     ¥È¤òÉÁ¤¯¡£
2018
2019     ¥Æ¥­¥¹¥È¤ÎÉÁ²èÊýË¡¤Ï mdraw_text () ¤È¤Û¤ÜƱ¤¸¤Ç¤¢¤ë¤¬¡¢¤³¤Î´Ø¿ô¤Ï
2020     ÉÁ²èÀ©¸æÍѤΥª¥Ö¥¸¥§¥¯¥È $CONTROL ¤Ç¤Î»Ø¼¨¤Ë¤â½¾¤¦ÅÀ¤¬°Û¤Ê¤Ã¤Æ¤¤¤ë¡£
2021
2022     ¤¿¤È¤¨¤Ð $CONTROL ¤Î <two_dimensional> ¤¬¥¼¥í¤Ç¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô
2023     ¤ÏM-text ¤ò2¼¡¸µÅª¤ËÉÁ¤¯¡£¤¹¤Ê¤ï¤Á M-text Ãæ¤Î²þ¹Ô¤Ç¹Ô¤ò²þ¤á¡¢Â³¤¯
2024     Ê¸»ú¤Ï¼¡¤Î¹Ô¤ËÉÁ¤¯¡£¾ÜºÙ¤Ï¹½Â¤ÂΠ@ MDrawControl ¤ÎÀâÌÀ¤ò»²¾È¤¹¤ë¤³
2025     ¤È¡£*/
2026
2027 int
2028 mdraw_text_with_control (MFrame *frame, MDrawWindow win, int x, int y,
2029                          MText *mt, int from, int to, MDrawControl *control)
2030 {
2031   M_CHECK_WRITABLE (frame, MERROR_DRAW, -1);
2032   return draw_text (frame, win, x, y, mt, from, to, control);
2033 }
2034
2035 /*=*/
2036
2037 /***en
2038     @brief Compute text pixel width.
2039
2040     The mdraw_text_extents () function computes the width of text
2041     between $FROM and $TO of M-text $MT when it is drawn on a window
2042     of frame $FRAME using the mdraw_text_with_control () function with
2043     the drawing control object $CONTROL.
2044
2045     If $OVERALL_INK_RETURN is not @c NULL, this function also computes
2046     the bounding box of character ink of the M-text, and stores the
2047     results in the members of the structure pointed to by
2048     $OVERALL_INK_RETURN.  If the M-text has a face specifying a
2049     surrounding box, the box is included in the bounding box.
2050
2051     If $OVERALL_LOGICAL_RETURN is not @c NULL, this function also
2052     computes the bounding box that provides mininum spacing to other
2053     graphical features (such as surrounding box) for the M-text, and
2054     stores the results in the members of the structure pointed to by
2055     $OVERALL_LOGICAL_RETURN.
2056
2057     If $OVERALL_LINE_RETURN is not @c NULL, this function also
2058     computes the bounding box that provides mininum spacing to the
2059     other M-text drawn, and stores the results in the members of the
2060     structure pointed to by $OVERALL_LINE_RETURN.  This is a union of
2061     $OVERALL_INK_RETURN and $OVERALL_LOGICAL_RETURN if the members
2062     min_line_ascent, min_line_descent, max_line_ascent, and
2063     max_line_descent of $CONTROL are all zero.
2064
2065     @return
2066     This function returns the width of the text to be drawn in the
2067     unit of pixels.  If $CONTROL->two_dimensional is nonzero and the
2068     text is drawn in multiple physical lines, it returns the width of
2069     the widest line.  If an error occurs, it returns -1 and assigns an
2070     error code to the external variable #merror_code.  */
2071
2072
2073 /***ja 
2074     @brief ¥Æ¥­¥¹¥È¤ÎÉý¡Ê¥Ô¥¯¥»¥ëñ°Ì¡Ë¤ò·×»»¤¹¤ë.
2075
2076     ´Ø¿ô mdraw_text_extents () ¤Ï¡¢´Ø¿ô mdraw_text_with_control () ¤¬
2077     ÉÁ²èÀ©¸æ¥ª¥Ö¥¸¥§¥¯¥È $CONTROL ¤òÍѤ¤¤Æ M-text $MT ¤Î $FROM ¤«¤é $TO 
2078     ¤Þ¤Ç¤ò¥Õ¥ì¡¼¥à $FRAME ¤Ëɽ¼¨¤¹¤ëºÝ¤ËɬÍפȤʤëÉý¤òÊÖ¤¹¡£
2079
2080     $OVERALL_INK_RETURN ¤¬ @c NULL ¤Ç¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï M-text ¤Îʸ
2081     »ú¤Î¥¤¥ó¥¯¤Î¥Ð¥¦¥ó¥Ç¥£¥ó¥°¥Ü¥Ã¥¯¥¹¤â·×»»¤·¡¢$OVERALL_INK_RETURN ¤¬
2082     »Ø¤¹¹½Â¤ÂΤΥá¥ó¥Ð¤Ë¤½¤Î·ë²Ì¤òÀßÄꤹ¤ë¡£M-text ¤Ë°Ï¤ßÏÈ(surrounding box)
2083     ¤ò»ØÄꤹ¤ë¥Õ¥§¡¼¥¹¤¬¤¢¤ì¤Ð¡¢¤½¤ì¤â¥Ð¥¦¥ó¥Ç¥£¥ó¥°¥Ü¥Ã¥¯¥¹¤Ë´Þ¤à¡£
2084
2085     $OVERALL_LOGICAL_RETURN ¤¬ @c NULL ¤Ç¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï M-text 
2086     ¤È¾¤Î graphical feature ¡Ê°Ï¤ßÏȤʤɡˤȤδ֤κǾ®¤Î¥¹¥Ú¡¼¥¹¤ò¼¨
2087     ¤¹¥Ð¥¦¥ó¥Ç¥£¥ó¥°¥Ü¥Ã¥¯¥¹¤â·×»»¤·¡¢$OVERALL_LOGICAL_RETURN ¤¬»Ø¤¹¹½
2088     Â¤ÂΤΥá¥ó¥Ð¤Ë¤½¤Î·ë²Ì¤òÀßÄꤹ¤ë¡£
2089
2090     $OVERALL_LINE_RETURN ¤¬ @c NULL ¤Ç¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï¾¤Î M-text 
2091     ¤È¤Î´Ö¤ÎºÇ¾®¤Î¥¹¥Ú¡¼¥¹¤ò¼¨¤¹¥Ð¥¦¥ó¥Ç¥£¥ó¥°¥Ü¥Ã¥¯¥¹¤â·×»»¤·¡¢
2092     $OVERALL_LINE_RETURN ¤¬»Ø¤¹¹½Â¤ÂΤΥá¥ó¥Ð¤Ë¤½¤Î·ë²Ì¤òÀßÄꤹ¤ë¡£¥ª
2093     ¥Ö¥¸¥§¥¯¥È $CONTROL ¤Î¥á¥ó¥Ð min_line_ascent, min_line_descent,
2094     max_line_ascent, max_line_descent ¤¬¤¹¤Ù¤Æ0¤Î»þ¤Ë¤Ï¡¢¤³¤ÎÃͤϠ
2095     $OVERALL_INK_RETURN ¤È$OVERALL_LOGICAL_RETURN ¤ÎϤȤʤ롣
2096
2097     @return ¤³¤Î´Ø¿ô¤Ïɽ¼¨¤ËɬÍפʥƥ­¥¹¥È¤ÎÉý¤ò¥Ô¥¯¥»¥ëñ°Ì¤ÇÊÖ¤¹¡£
2098     $CONTROL->two_dimensional ¤¬0¤Ç¤Ê¤¯¡¢¥Æ¥­¥¹¥È¤¬Ê£¿ô¤Î¹Ô¤ËÅϤäÆÉÁ
2099     ¤«¤ì¤ë¾ì¹ç¤Ë¤Ï¡¢ºÇÂç¤ÎÉý¤òÊÖ¤¹¡£¥¨¥é¡¼¤¬À¸¤¸¤¿¾ì¹ç¤Ï -1 ¤òÊÖ¤·¡¢³°
2100     ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
2101
2102     @latexonly \IPAlabel{mdraw_text_extents} @endlatexonly  */
2103
2104 /***
2105     @errors
2106     @c MERROR_RANGE  */
2107
2108 int
2109 mdraw_text_extents (MFrame *frame,
2110                     MText *mt, int from, int to, MDrawControl *control,
2111                     MDrawMetric *overall_ink_return,
2112                     MDrawMetric *overall_logical_return,
2113                     MDrawMetric *overall_line_return)
2114 {
2115   MGlyphString *gstring;
2116   int y = 0;
2117   int width, rbearing;
2118
2119   ASSURE_CONTROL (control);
2120   M_CHECK_POS_X (mt, from, -1);
2121   if (to > mtext_nchars (mt) + (control->cursor_width != 0))
2122     to = mtext_nchars (mt) + (control->cursor_width != 0);
2123   else if (to < from)
2124     to = from;
2125
2126   gstring = get_gstring (frame, mt, from, to, control);
2127   if (! gstring)
2128     MERROR (MERROR_DRAW, -1);
2129   width = gstring_width (gstring, from, to, &rbearing);
2130   if (overall_ink_return)
2131     {
2132       overall_ink_return->y = - gstring->physical_ascent;
2133       overall_ink_return->x = gstring->lbearing;
2134     }
2135   if (overall_logical_return)
2136     {
2137       overall_logical_return->y = - gstring->ascent;
2138       overall_logical_return->x = 0;
2139     }
2140   if (overall_line_return)
2141     {
2142       overall_line_return->y = - gstring->line_ascent;
2143       overall_line_return->x = gstring->lbearing;
2144     }
2145
2146   for (from = gstring->to; from < to; from = gstring->to)
2147     {
2148       int this_width, this_rbearing;
2149
2150       y += gstring->line_descent;
2151       M17N_OBJECT_UNREF (gstring->top);
2152       gstring = get_gstring (frame, mt, from, to, control);
2153       this_width = gstring_width (gstring, from, to, &this_rbearing);
2154       y += gstring->line_ascent;
2155       if (width < this_width)
2156         width = this_width;
2157       if (rbearing < this_rbearing)
2158         rbearing = this_rbearing;
2159     }
2160   if (overall_ink_return)
2161     {
2162       overall_ink_return->width = rbearing;
2163       overall_ink_return->height
2164         = y + gstring->physical_descent - overall_ink_return->y;
2165     }
2166   if (overall_logical_return)
2167     {
2168       overall_logical_return->width = width;
2169       overall_logical_return->height
2170         = y + gstring->descent - overall_logical_return->y;
2171     }
2172   if (overall_line_return)
2173     {
2174       overall_line_return->width = MAX (width, rbearing);
2175       overall_line_return->height
2176         = y + gstring->line_descent - overall_line_return->y;
2177     }
2178
2179   M17N_OBJECT_UNREF (gstring->top);
2180   return width;
2181 }
2182
2183 /*=*/
2184
2185 /***en
2186     @brief Compute the text dimensions of each character of M-text.
2187
2188     The mdraw_text_per_char_extents () function computes the drawn
2189     metric of each character between $FROM and $TO of M-text $MT
2190     assuming that they are drawn on a window of frame $FRAME using the
2191     mdraw_text_with_control () function with the drawing control
2192     object $CONTROL.
2193
2194     $ARRAY_SIZE specifies the size of $INK_ARRAY_RETURN and
2195     $LOGICAL_ARRAY_RETURN.  Each successive element of
2196     $INK_ARRAY_RETURN and $LOGICAL_ARRAY_RETURN are set to the drawn
2197     ink and logical metrics of successive characters respectively,
2198     relative to the drawing origin of the M-text.  The number of
2199     elements of $INK_ARRAY_RETURN and $LOGICAL_ARRAY_RETURN that have
2200     been set is returned to $NUM_CHARS_RETURN.
2201
2202     If $ARRAY_SIZE is too small to return all metrics, the function
2203     returns -1 and store the requested size in $NUM_CHARS_RETURN.
2204     Otherwise, it returns zero.
2205
2206     If pointer $OVERALL_INK_RETURN and $OVERALL_LOGICAL_RETURN are not
2207     @c NULL, this function also computes the metrics of the overall
2208     text and stores the results in the members of the structure
2209     pointed to by $OVERALL_INK_RETURN and $OVERALL_LOGICAL_RETURN.
2210
2211     If $CONTROL->two_dimensional is nonzero, this function computes
2212     only the metrics of characters in the first line.  */
2213 /***ja
2214     @brief  M-text ¤Î³Æʸ»ú¤Îɽ¼¨ÈϰϤò·×»»¤¹¤ë.
2215
2216     ´Ø¿ô mdraw_text_per_char_extents () ¤Ï¡¢´Ø¿ô 
2217     mdraw_text_with_control () ¤¬ÉÁ²èÀ©¸æ¥ª¥Ö¥¸¥§¥¯¥È $CONTROL ¤òÍѤ¤
2218     ¤Æ M-text $MT ¤Î $FROM ¤«¤é $TO ¤Þ¤Ç¤ò¥Õ¥ì¡¼¥à $FRAME ¤Ëɽ¼¨¤¹¤ëºÝ
2219     ¤Î³Æʸ»ú¤Î¥µ¥¤¥º¤ò·×»»¤¹¤ë¡£
2220
2221     $ARRAY_SIZE ¤Ë¤è¤Ã¤Æ $INK_ARRAY_RETURN ¤È$LOGICAL_ARRAY_RETURN ¤Î
2222     ¥µ¥¤¥º¤ò»ØÄꤹ¤ë¡£$INK_ARRAY_RETURN ¤È$LOGICAL_ARRAY_RETURN ¤Î³ÆÍ×
2223     ÁǤϡ¢¤½¤ì¤¾¤ìʸ»ú¤ÎÉÁ²è¥¤¥ó¥¯¤ÈÏÀÍý¥µ¥¤¥º¡ÊM-text¤Îɽ¼¨¸¶ÅÀ¤«¤é¤Î
2224     ÁêÂаÌÃ͡ˤˤè¤Ã¤Æ½ç¤ËËä¤á¤é¤ì¤ë¡£ÀßÄꤵ¤ì¤¿ $INK_ARRAY_RETURN ¤È 
2225     $LOGICAL_ARRAY_RETURN ¤ÎÍ×ÁǤοô¤Ï¡¢$NUM_CHARS_RETURN ¤ËÌᤵ¤ì¤ë¡£
2226    
2227     $ARRAY_SIZE ¤¬¤¹¤Ù¤Æ¤ÎÀ£Ë¡¤òÌ᤻¤Ê¤¤¤Û¤É¾®¤µ¤¤¾ì¹ç¤Ë¤Ï¡¢´Ø¿ô¤Ï -1 
2228     ¤òÊÖ¤·¡¢É¬ÍפÊÂ礭¤µ¤ò $NUM_CHARS_RETURN ¤ËÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð 0 
2229     ¤òÊÖ¤¹¡£
2230
2231     ¥Ý¥¤¥ó¥¿ $OVERALL_INK_RETURN ¤È $OVERALL_LOGICAL_RETURN ¤¬@c NULL 
2232     ¤Ç¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï¥Æ¥­¥¹¥ÈÁ´ÂΤΥµ¥¤¥º¤â·×»»¤·¡¢·ë²Ì¤ò
2233     $OVERALL_INK_RETURN ¤È $OVERALL_LOGICAL_RETURN ¤Ç»Ø¤µ¤ì¤ë¹½Â¤¤Î¥á
2234     ¥ó¥Ð¤ËÊݸ¤¹¤ë¡£
2235
2236     $CONTROL->two_dimensional ¤¬0¤Ç¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤ÏºÇ½é¤Î¹Ô¤Îʸ»ú
2237     ¤Î¥µ¥¤¥º¤À¤±¤ò·×»»¤¹¤ë¡£ */
2238
2239 int
2240 mdraw_text_per_char_extents (MFrame *frame,
2241                              MText *mt, int from, int to,
2242                              MDrawControl *control,
2243                              MDrawMetric *ink_array_return,
2244                              MDrawMetric *logical_array_return,
2245                              int array_size,
2246                              int *num_chars_return,
2247                              MDrawMetric *overall_ink_return,
2248                              MDrawMetric *overall_logical_return)
2249 {
2250   MGlyphString *gstring;
2251   MGlyph *g;
2252   int x;
2253
2254   ASSURE_CONTROL (control);
2255   *num_chars_return = to - from;
2256   if (array_size < *num_chars_return)
2257     MERROR (MERROR_DRAW, -1);
2258   if (overall_logical_return)
2259     memset (overall_logical_return, 0, sizeof (MDrawMetric));
2260   if (overall_ink_return)
2261     memset (overall_ink_return, 0, sizeof (MDrawMetric));
2262
2263   M_CHECK_RANGE (mt, from, to, -1, 0);
2264   gstring = get_gstring (frame, mt, from, to, control);
2265   if (! gstring)
2266     {
2267       *num_chars_return = 0;
2268       return 0;
2269     }
2270
2271   for (g = MGLYPH (1), x = 0; g->type != GLYPH_ANCHOR;)
2272     if (g->pos >= from && g->pos < to)
2273       {
2274         int start = g->pos;
2275         int end = g->to;
2276         int width = g->width;
2277         int lbearing = g->lbearing;
2278         int rbearing = g->rbearing;
2279         int ascent = g->ascent;
2280         int descent = g->descent;
2281         int logical_ascent = g->rface->rfont->ascent;
2282         int logical_descent = g->rface->rfont->descent;
2283
2284         for (g++; g->type != GLYPH_ANCHOR && g->pos == start; g++)
2285           {
2286             if (lbearing < width + g->lbearing)
2287               lbearing = width + g->lbearing;
2288             if (rbearing < width + g->rbearing)
2289               rbearing = width + g->rbearing;
2290             width += g->width;
2291             if (ascent < g->ascent)
2292               ascent = g->ascent;
2293             if (descent < g->descent)
2294               descent = g->descent;
2295           }
2296
2297         if (end > to)
2298           end = to;
2299         while (start < end)
2300           {
2301             ink_array_return[start - from].x = x + lbearing;
2302             ink_array_return[start - from].y = - ascent;
2303             ink_array_return[start - from].width = rbearing - lbearing;
2304             ink_array_return[start - from].height = ascent + descent;
2305             logical_array_return[start - from].x = x;
2306             logical_array_return[start - from].y = - logical_descent;
2307             logical_array_return[start - from].height
2308               = logical_ascent + logical_descent;
2309             logical_array_return[start - from].width = width;
2310             start++;
2311           }
2312         x += width;
2313       }
2314
2315   if (overall_ink_return)
2316     {
2317       overall_ink_return->y = - gstring->line_ascent;
2318       overall_ink_return->x = gstring->lbearing;
2319       overall_ink_return->width = x - gstring->lbearing;
2320       overall_ink_return->height = gstring->height;
2321     }
2322   if (overall_logical_return)
2323     {
2324       overall_logical_return->y = - gstring->ascent;
2325       overall_logical_return->x = 0;
2326       overall_logical_return->width = x;
2327       overall_logical_return->height = gstring->ascent + gstring->descent;
2328     }
2329
2330   M17N_OBJECT_UNREF (gstring->top);
2331   return 0;
2332 }
2333
2334 /*=*/
2335
2336 /***en
2337     @brief Return the character position nearest to the coordinates.
2338
2339     The mdraw_coordinates_position () function checks which character
2340     is to be drawn at coordinate ($X, $Y) when the text between $FROM
2341     and $TO of M-text $MT is drawn at the coordinate (0, 0) using the
2342     mdraw_text_with_control () function with the drawing control
2343     object $CONTROL.  Here, the character position means the number of
2344     characters that precede the character in question in $MT, that is,
2345     the character position of the first character is 0.
2346
2347     $FRAME is used only to get the default face information.
2348
2349     @return
2350     If the glyph image of a character covers coordinate ($X, $Y),
2351     mdraw_coordinates_position () returns the character position of
2352     that character.\n\n
2353     If $Y is less than the minimum Y-coordinate of the drawn area, it
2354     returns $FROM.\n\n\n
2355     If $Y is greater than the maximum Y-coordinate of the drawn area,
2356     it returns $TO.\n\n\n
2357     If $Y fits in with the drawn area but $X is less than the minimum
2358     X-coordinate, it returns the character position of the first
2359     character drawn on the line $Y.\n\n\n
2360     If $Y fits in with the drawn area but $X is greater than the
2361     maximum X-coordinate, it returns the character position of the
2362     last character drawn on the line $Y.  */
2363
2364 /***ja
2365     @brief »ØÄꤷ¤¿ºÂɸ¤ËºÇ¤â¶á¤¤Ê¸»ú¤Îʸ»ú°ÌÃÖ¤òÆÀ¤ë.
2366
2367     ´Ø¿ô mdraw_coordinates_position () ¤Ï¡¢´Ø¿ô 
2368     mdraw_text_with_control () ¤¬ÉÁ²èÀ©¸æ¥ª¥Ö¥¸¥§¥¯¥È $CONTROL ¤òÍѤ¤
2369     ¤ÆM-text $MT ¤Î $FROM ¤«¤é $TO ¤Þ¤Ç¤òºÂɸ (0, 0) ¤òµ¯ÅÀ¤È¤·¤ÆÉÁ²è
2370     ¤·¤¿¾ì¹ç¤Ë¡¢ºÂɸ ($X, $Y) ¤ËÉÁ²è¤µ¤ì¤ëʸ»ú¤Îʸ»ú°ÌÃÖ¤òÊÖ¤¹¡£¤³¤³¤Ç
2371     Ê¸»ú°ÌÃ֤Ȥϡ¢Åö³º M-text Ãæ¤Ë¤ª¤¤¤Æ¤½¤Îʸ»ú¤¬ºÇ½é¤«¤é²¿ÈÖÌܤ«¤ò¼¨
2372     ¤¹À°¿ô¤Ç¤¢¤ë¡£¤¿¤À¤·ºÇ½é¤Îʸ»ú¤Îʸ»ú°ÌÃÖ¤Ï0¤È¤¹¤ë¡£
2373
2374     $FRAME ¤Ï¥Ç¥Õ¥©¥ë¥È¤Î¥Õ¥§¡¼¥¹¤Î¾ðÊó¤òÆÀ¤ë¤¿¤á¤À¤±¤ËÍѤ¤¤é¤ì¤ë¡£
2375
2376     @return
2377     ºÂɸ ($X, $Y) ¤¬¤¢¤ëʸ»ú¤Î¥°¥ê¥Õ¤Çʤ¤ï¤ì¤ë¾ì¹ç¡¢ ´Ø¿ô 
2378     mdraw_coordinates_position () ¤Ï¤½¤Îʸ»ú¤Îʸ»ú°ÌÃÖ¤òÊÖ¤¹¡£
2379
2380     ¤â¤· $Y ¤¬ÉÁ²èÎΰè¤ÎºÇ¾®YºÂɸ¤è¤ê¤â¾®¤µ¤¤¤Ê¤é¤Ð $FROM ¤òÊÖ¤¹¡£
2381
2382     ¤â¤· $Y ¤¬ÉÁ²èÎΰè¤ÎºÇÂçYºÂɸ¤è¤ê¤âÂ礭¤¤¤Ê¤é¤Ð $TO ¤òÊÖ¤¹¡£
2383
2384     ¤â¤· $Y ¤¬ÉÁ²èÎΰè¤Ë¾è¤Ã¤Æ¤¤¤Æ¤«¤Ä $X ¤¬ÉÁ²èÎΰè¤ÎºÇ¾®XºÂɸ¤è¤ê¤â
2385     ¾®¤µ¤¤¾ì¹ç¤Ï¡¢Ä¾Àþ y = $Y ¾å¤ËÉÁ²è¤µ¤ì¤ëºÇ½é¤Îʸ»ú¤Îʸ»ú°ÌÃÖ¤òÊÖ¤¹¡£
2386
2387     ¤â¤· $Y ¤¬ÉÁ²èÎΰè¤Ë¾è¤Ã¤Æ¤¤¤Æ¤«¤Ä $X ¤¬ÉÁ²èÎΰè¤ÎºÇÂçXºÂɸ¤è¤ê¤â
2388     Â礭¤¤¾ì¹ç¤Ï¡¢Ä¾Àþ y = $Y ¾å¤ËÉÁ²è¤µ¤ì¤ëºÇ¸å¤Îʸ»ú¤Îʸ»ú°ÌÃÖ¤òÊÖ¤¹¡£ */
2389
2390 int
2391 mdraw_coordinates_position (MFrame *frame, MText *mt, int from, int to,
2392                             int x_offset, int y_offset, MDrawControl *control)
2393 {
2394   MGlyphString *gstring;
2395   int y = 0;
2396   int width;
2397   MGlyph *g;
2398
2399   M_CHECK_POS_X (mt, from, -1);
2400   if (to > mtext_nchars (mt) + (control->cursor_width != 0))
2401     to = mtext_nchars (mt) + (control->cursor_width != 0);
2402   else if (to < from)
2403     to = from;
2404
2405   if (from == to)
2406     return from;
2407   ASSURE_CONTROL (control);
2408   gstring = get_gstring (frame, mt, from, to, control);
2409   while (y + gstring->line_descent <= y_offset
2410          && gstring->to < to)
2411     {
2412       from = gstring->to;
2413       y += gstring->line_descent;
2414       M17N_OBJECT_UNREF (gstring->top);
2415       gstring = get_gstring (frame, mt, from, to, control);
2416       y += gstring->line_ascent;
2417     }
2418
2419   /* Accumulate width of glyphs in WIDTH until it exceeds X. */
2420   if (! control->orientation_reversed)
2421     {
2422       width = gstring->indent;
2423       for (g = MGLYPH (1); g[1].type != GLYPH_ANCHOR; g++)
2424         if (g->pos >= from && g->pos < to)
2425           {
2426             width += g->width;
2427             if (width > x_offset)
2428               break;
2429           }
2430     }
2431   else
2432     {
2433       width = - gstring->indent;
2434       for (g = MGLYPH (gstring->used - 2); g->type != GLYPH_ANCHOR; g--)
2435         if (g->pos >= from && g->pos < to)
2436           {
2437             width -= g->width;
2438             if (width < x_offset)
2439               break;
2440           }
2441     }
2442   from = g->pos;
2443   M17N_OBJECT_UNREF (gstring->top);
2444
2445   return from;
2446 }
2447
2448 /*=*/
2449
2450 /***en
2451     @brief Compute information about a glyph.
2452
2453     The mdraw_glyph_info () function computes information about a
2454     glyph that covers a character at position $POS of the M-text $MT
2455     assuming that the text is drawn from the character at $FROM of $MT
2456     on a window of frame $FRAME using the mdraw_text_with_control ()
2457     function with the drawing control object $CONTROL.
2458
2459     The information is stored in the members of $INFO.  */
2460 /***ja
2461     @brief ¥°¥ê¥Õ¤Ë´Ø¤¹¤ë¾ðÊó¤ò·×»»¤¹¤ë.
2462
2463     ´Ø¿ô mdraw_glyph_info () ¤Ï¡¢´Ø¿ô mdraw_text_with_control () ¤¬ÉÁ
2464     ²èÀ©¸æ¥ª¥Ö¥¸¥§¥¯¥È $CONTROL ¤òÍѤ¤¤ÆM-text $MT ¤Î $FROM ¤«¤é $TO 
2465     ¤Þ¤Ç¤ò¥Õ¥ì¡¼¥à $FRAME ¤ËÉÁ²è¤·¤¿¾ì¹ç¡¢M-text ¤Îʸ»ú°ÌÃÖ $POS ¤Îʸ
2466     »ú¤òʤ¤¦¥°¥ê¥Õ¤Ë´Ø¤¹¤ë¾ðÊó¤ò·×»»¤¹¤ë¡£
2467
2468     ¾ðÊó¤Ï$INFO ¤Î¥á¥ó¥Ð¤ËÊÝ»ý¤µ¤ì¤ë¡£  */
2469
2470 /***
2471     @seealso
2472     MDrawGlyphInfo
2473 */
2474
2475 int
2476 mdraw_glyph_info (MFrame *frame, MText *mt, int from, int pos,
2477                   MDrawControl *control, MDrawGlyphInfo *info)
2478 {
2479   MGlyphString *gstring;
2480   MGlyph *g;
2481   int y = 0;
2482
2483   M_CHECK_RANGE_X (mt, from, pos, -1);
2484
2485   ASSURE_CONTROL (control);
2486   gstring = get_gstring (frame, mt, from, pos + 1, control);
2487   if (! gstring)
2488     MERROR (MERROR_DRAW, -1);
2489   while (gstring->to <= pos)
2490     {
2491       y += gstring->line_descent;
2492       M17N_OBJECT_UNREF (gstring->top);
2493       gstring = get_gstring (frame, mt, gstring->to, pos + 1, control);
2494       y += gstring->line_ascent;
2495     }
2496   info->line_from = gstring->from;
2497   if (info->line_from < from)
2498     info->line_from = from;
2499   info->line_to = gstring->to;
2500
2501   info->y = y;
2502   if (! control->orientation_reversed)
2503     {
2504       info->x = gstring->indent;
2505       for (g = MGLYPH (1); g->pos > pos || g->to <= pos; g++)
2506         info->x += g->width;
2507     }
2508   else
2509     {
2510       info->x = - gstring->indent;
2511       for (g = MGLYPH (gstring->used - 2); g->pos > pos || g->to <= pos; g--)
2512         info->x -= g->width;
2513       while (g[-1].to == g->to)
2514         g--;
2515     }
2516   info->from = g->pos;
2517   info->to = g->to;
2518   info->glyph_code = g->code;
2519   info->this.x = g->lbearing;
2520   info->this.y = - gstring->line_ascent;
2521   info->this.height = gstring->height;
2522   info->this.width = - g->lbearing + g->width;
2523   if (g->rface->rfont)
2524     info->font = &g->rface->rfont->font;
2525   else
2526     info->font = NULL;
2527   /* info->logical_width is calculated later.  */
2528
2529   if (info->from > info->line_from)
2530     {
2531       /* The logically previous glyph is on this line.  */
2532       MGlyph *g_tmp = find_glyph_in_gstring (gstring, info->from - 1, 1);
2533
2534       info->prev_from = g_tmp->pos;
2535     }
2536   else if (info->line_from > 0)
2537     {
2538       /* The logically previous glyph is on the previous line.  */
2539       MGlyphString *gst = get_gstring (frame, mt, gstring->from - 1,
2540                                        gstring->from, control);
2541       MGlyph *g_tmp = find_glyph_in_gstring (gst, info->from - 1, 1);
2542
2543       info->prev_from = g_tmp->pos;
2544       M17N_OBJECT_UNREF (gst->top);
2545     }
2546   else
2547     info->prev_from = -1;
2548
2549   if (GLYPH_INDEX (g) > 1)
2550     info->left_from = g[-1].pos, info->left_to = g[-1].to;
2551   else if (! control->orientation_reversed)
2552     {
2553       if (info->line_from > 0)
2554         {
2555           MGlyph *g_tmp;
2556           MGlyphString *gst;
2557           int p = gstring->from - 1;
2558
2559           gst = get_gstring (frame, mt, p, gstring->from, control);
2560           g_tmp = gst->glyphs + (gst->used - 2);
2561           info->left_from = g_tmp->pos, info->left_to = g_tmp->to;
2562           M17N_OBJECT_UNREF (gst->top);
2563         }
2564       else
2565         info->left_from = info->left_to = -1;
2566     }
2567   else
2568     {
2569       if (gstring->to + (control->cursor_width == 0) <= mtext_nchars (mt))
2570         {
2571           MGlyph *g_tmp;
2572           MGlyphString *gst;
2573           int p = gstring->to;
2574
2575           gst = get_gstring (frame, mt, p, p + 1, control);
2576           g_tmp = gst->glyphs + (gst->used - 2);
2577           info->left_from = g_tmp->pos, info->left_to = g_tmp->to;
2578           M17N_OBJECT_UNREF (gst->top);
2579         }
2580       else
2581         info->left_from = info->left_to = -1;
2582     }
2583
2584   if (info->to < gstring->to)
2585     {
2586       /* The logically next glyph is on this line.   */
2587       MGlyph *g_tmp = find_glyph_in_gstring (gstring, info->to, 0);
2588
2589       info->next_to = g_tmp->to;
2590     }
2591   else if (info->to + (control->cursor_width == 0) <= mtext_nchars (mt))
2592     {
2593       /* The logically next glyph is on the next line.   */
2594       int p = info->to;
2595       MGlyphString *gst = get_gstring (frame, mt, p, p + 1, control);
2596       MGlyph *g_tmp = find_glyph_in_gstring (gst, p, 0);
2597
2598       info->next_to = g_tmp->to;
2599       M17N_OBJECT_UNREF (gst->top);
2600     }
2601   else
2602     info->next_to = -1;
2603
2604   for (info->logical_width = (g++)->width;
2605        g->pos == pos && g->type != GLYPH_ANCHOR;
2606        info->this.width += g->width, info->logical_width += (g++)->width);
2607   info->this.width += g[-1].rbearing - g[-1].width;
2608
2609   if (g->type != GLYPH_ANCHOR)
2610     info->right_from = g->pos, info->right_to = g->to;
2611   else if (! control->orientation_reversed)
2612     {
2613       if (gstring->to + (control->cursor_width == 0) <= mtext_nchars (mt))
2614         {
2615           pos = gstring->to;
2616           M17N_OBJECT_UNREF (gstring->top);
2617           gstring = get_gstring (frame, mt, pos, pos + 1, control);
2618           g = MGLYPH (1);
2619           info->right_from = g->pos, info->right_to = g->to;
2620         }
2621       else
2622         info->right_from = info->right_to = -1;
2623     }
2624   else
2625     {
2626       if (info->line_from > 0)
2627         {
2628           pos = gstring->from - 1;
2629           M17N_OBJECT_UNREF (gstring->top);
2630           gstring = get_gstring (frame, mt, pos, pos + 1, control);
2631           g = MGLYPH (1);
2632           info->right_from = g->pos, info->right_to = g->to;
2633         }
2634       else
2635         info->right_from = info->right_to = -1;
2636     }
2637
2638   M17N_OBJECT_UNREF (gstring->top);
2639   return 0;
2640 }
2641
2642 /*=*/
2643
2644 int
2645 mdraw_glyph_list (MFrame *frame, MText *mt, int from, int to,
2646                   MDrawControl *control, MDrawGlyphInfo *info,
2647                   int array_size, int *num_glyphs_return)
2648 {
2649   MGlyphString *gstring;
2650   MGlyph *g;
2651   int n;
2652
2653   ASSURE_CONTROL (control);
2654   *num_glyphs_return = 0;
2655   M_CHECK_RANGE (mt, from, to, -1, 0);
2656   gstring = get_gstring (frame, mt, from, to, control);
2657   if (! gstring)
2658     return -1;
2659   for (g = MGLYPH (1), n = 0; g->type != GLYPH_ANCHOR; g++)
2660     {
2661       if (g->type == GLYPH_BOX
2662           || g->pos < from || g->pos >= to)
2663         continue;
2664       if (n < array_size)
2665         {
2666           info->from = g->pos;
2667           info->to = g->to;
2668           if (g->type == GLYPH_CHAR)
2669             info->glyph_code = g->code;
2670           else
2671             info->glyph_code = mfont__encode_char (g->rface->rfont, ' ');
2672           info->x = g->xoff;
2673           info->y = g->yoff;
2674           info->this.x = g->lbearing;
2675           info->this.y = - g->ascent;
2676           info->this.height = g->ascent + g->descent;
2677           info->this.width = g->rbearing - g->lbearing;
2678           info->logical_width = g->width;
2679           if (g->rface->rfont)
2680             info->font = &g->rface->rfont->font;
2681           else
2682             info->font = NULL;
2683           info++;
2684         }
2685       n++;
2686     }
2687   M17N_OBJECT_UNREF (gstring->top);
2688
2689   *num_glyphs_return = n;
2690   return (n <= array_size ? 0 : -1);
2691 }
2692
2693 /*=*/
2694
2695 /***en
2696     @brief Draw one or more textitems.
2697
2698     The mdraw_text_items () function draws one or more M-texts on
2699     window $WIN of $FRAME at coordinate ($X, $Y).  $ITEMS is an array
2700     of the textitems to be drawn and $NITEMS is the number of
2701     textimtems in the array.  */
2702
2703 /***ja
2704     @brief textitem ¤òɽ¼¨¤¹¤ë.
2705
2706     ´Ø¿ô mdraw_text_items () ¤Ï¡¢°ì¸Ä°Ê¾å¤Î¥Æ¥­¥¹¥È¥¢¥¤¥Æ¥à¤ò¡¢¥Õ¥ì¡¼
2707     ¥à $FRAME ¤Î¥¦¥£¥ó¥É¥¦ $WIN ¤ÎºÂɸ ($X, $Y) ¤Ëɽ¼¨¤¹¤ë¡£$ITEMS ¤Ï
2708     É½¼¨¤¹¤Ù¤­¥Æ¥­¥¹¥È¥¢¥¤¥Æ¥à¤ÎÇÛÎó¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ê¡¢$NITEMS ¤Ï¤½¤Î
2709     ¸Ä¿ô¤Ç¤¢¤ë¡£
2710
2711     @latexonly \IPAlabel{mdraw_text_items} @endlatexonly  */
2712
2713 /***
2714     @seealso
2715     MTextItem, mdraw_text ().  */
2716
2717 void
2718 mdraw_text_items (MFrame *frame, MDrawWindow win, int x, int y,
2719                   MDrawTextItem *items, int nitems)
2720 {
2721   if (! (frame->device_type & MDEVICE_SUPPORT_OUTPUT))
2722     return;
2723   while (nitems-- > 0)
2724     {
2725       if (items->face)
2726         mtext_push_prop (items->mt, 0, mtext_nchars (items->mt), Mface,
2727                          items->face);
2728       mdraw_text_with_control (frame, win, x, y,
2729                                items->mt, 0, mtext_nchars (items->mt),
2730                                items->control);
2731       x += mdraw_text_extents (frame, items->mt, 0, mtext_nchars (items->mt),
2732                                items->control, NULL, NULL, NULL);
2733       x += items->delta;
2734       if (items->face)
2735         mtext_pop_prop (items->mt, 0, mtext_nchars (items->mt), Mface);
2736     }
2737 }
2738
2739 /*=*/
2740 /***en 
2741       @brief   calculate a line breaking position.
2742
2743       The function mdraw_default_line_break () calculates a line
2744       breaking position based on the line number $LINE and the
2745       coordinate $Y, when a line is too long to fit within the width
2746       limit.  $POS is the position of the character next to the last
2747       one that fits within the limit.  $FROM is the position of the
2748       first character of the line, and TO is the position of the last
2749       character displayed on the line if there were not width limit.
2750       LINE and Y are reset to 0 when a line is broken by a newline
2751       character, and incremented each time when a long line is broken
2752       because of the width limit.  
2753
2754       @return 
2755       This function returns a character position to break the
2756       line.
2757
2758 */
2759 /***ja 
2760       @brief ²þ¹Ô°ÌÃÖ¤ò·×»»¤¹¤ë.
2761
2762       ´Ø¿ô mdraw_default_line_break () ¤Ï¡¢¹Ô¤¬ºÇÂçÉýÃæ¤Ë¼ý¤Þ¤é¤Ê¤¤¾ì
2763       ¹ç¤Ë¹Ô¤ò²þ¤á¤ë°ÌÃÖ¤ò¡¢¹ÔÈÖ¹æ LINE ¤ÈºÂɸ Y ¤Ë´ð¤Å¤¤¤Æ·×»»¤¹¤ë¡£
2764       $POS ¤ÏºÇÂçÉý¤Ë¼ý¤Þ¤ëºÇ¸å¤Îʸ»ú¤Î¼¡¤Îʸ»ú¤Î°ÌÃ֤Ǥ¢¤ë¡£$FROM ¤Ï
2765       ¹Ô¤ÎºÇ½é¤Îʸ»ú¤Î°ÌÃÖ¡¢$TO ¤ÏºÇÂçÉý¤¬»ØÄꤵ¤ì¤Æ¤¤¤Ê¤±¤ì¤Ð¤½¤Î¹Ô¤Ë
2766       É½¼¨¤µ¤ì¤ëºÇ¸å¤Îʸ»ú¤Î°ÌÃ֤Ǥ¢¤ë¡£ LINE ¤È Y ¤Ï²þ¹Ôʸ»ú¤Ë¤è¤Ã¤Æ
2767       ¹Ô¤¬²þ¤Þ¤Ã¤¿ºÝ¤Ë¤Ï 0 ¤Ë¥ê¥»¥Ã¥È¤µ¤ì¡¢ºÇÂçÉý¤Ë¤è¤Ã¤Æ¹Ô¤¬²þ¤Þ¤Ã¤¿
2768       ¾ì¹ç¤Ë¤Ï 1 ¤Å¤ÄÁý¤ä¤µ¤ì¤ë¡£
2769
2770       @return 
2771       ¤³¤Î´Ø¿ô¤Ï¹Ô¤ò²þ¤á¤ëʸ»ú°ÌÃÖ¤òÊÖ¤¹¡£
2772 */
2773
2774 int
2775 mdraw_default_line_break (MText *mt, int pos,
2776                           int from, int to, int line, int y)
2777 {
2778   int c = mtext_ref_char (mt, pos);
2779   int orig_pos = pos;
2780
2781   if (c == ' ' || c == '\t')
2782     {
2783       pos++;
2784       while (pos < to
2785              && ((c = mtext_ref_char (mt, pos)) == ' ' || c == '\t'))
2786         pos++;
2787     }
2788   else
2789     {
2790       while (pos > from)
2791         {
2792           if (c == ' ' || c == '\t')
2793             break;
2794           pos--;
2795           c = mtext_ref_char (mt, pos);
2796         }
2797       if (pos == from)
2798         pos = orig_pos;
2799       else
2800         pos++;
2801     }
2802   return pos;
2803 }
2804
2805 /*=*/
2806
2807 /***en
2808     @brief Obtain per character dimension information.
2809
2810     The mdraw_per_char_extents () function computes the text dimension
2811     of each character in M-text $MT.  The faces given as text
2812     properties in $MT and the default face of frame $FRAME determine
2813     the fonts to draw the text.  Each successive element in
2814     $ARRAY_RETURN is set to the drawn metrics of successive
2815     characters, which is relative to the origin of the drawing, and a
2816     rectangle for each character in $MT.  The number of elements of
2817     $ARRAY_RETURN must be equal to or greater than the number of
2818     characters in $MT.
2819
2820     If pointer $OVERALL_RETURN is not @c NULL, this function also
2821     computes the extents of the overall text and stores the results in
2822     the members of the structure pointed to by $OVERALL_RETURN.  */
2823
2824 /***ja
2825     @brief M-text ¤Îʸ»úËè¤Îɽ¼¨ÈϰϾðÊó¤òÆÀ¤ë.
2826
2827     ´Ø¿ô mdraw_per_char_extents () ¤Ï¡¢M-text $MT Ãæ¤Î³Æʸ»ú¤Îɽ¼¨ÈÏ°Ï
2828     ¤ò·×»»¤¹¤ë¡£¤³¤Î·×»»¤ËÍѤ¤¤ë¥Õ¥©¥ó¥È¤Ï¡¢$MT ¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ç
2829     »ØÄꤵ¤ì¤¿¥Õ¥§¡¼¥¹¤Èa¡¢¥Õ¥ì¡¼¥à $FRAME ¤Î¥Ç¥Õ¥©¥ë¥È¥Õ¥§¡¼¥¹¤Ë¤è¤Ã¤Æ
2830     ·è¤Þ¤ë¡£$ARRAY_RETURN ¤Î³ÆÍ×ÁǤϡ¢Åö³º M-text Ãæ¤Î³Æʸ»ú¤Îɽ¼¨ÈÏ°Ï
2831     ¾ðÊó¤Ë¤è¤Ã¤Æ½ç¤ËËä¤á¤é¤ì¤ë¡£¤³¤Îɽ¼¨ÈϰϾðÊó¤Ï¡¢M-text ¤Îɽ¼¨¸¶ÅÀ¤«
2832     ¤é¤ÎÁêÂаÌÃ֤Ǥ¢¤ë¡£$ARRAY_RETURN ¤ÎÍ×ÁÇ¿ô¤Ï¡¢M-text ¤Î°Ê¾å¤Ç¤Ê¤±¤ì
2833     ¤Ð¤Ê¤é¤Ê¤¤¡£
2834
2835     ¥Ý¥¤¥ó¥¿ $OVERALL_RETURN ¤¬ @c NULL ¤Ç¤Ê¤¤¾ì¹ç¤Ï¡¢¥Æ¥­¥¹¥ÈÁ´ÂΤÎɽ
2836     ¼¨ÈϰϾðÊó¤â·×»»¤·¡¢¤½¤Î·ë²Ì¤ò $OVERALL_RETURN ¤Î»Ø¤¹¹½Â¤ÂΤ˳ÊǼ
2837     ¤¹¤ë¡£
2838
2839     @latexonly \IPAlabel{mdraw_per_char_extents} @endlatexonly  */
2840
2841 void
2842 mdraw_per_char_extents (MFrame *frame, MText *mt,
2843                         MDrawMetric *array_return,
2844                         MDrawMetric *overall_return)
2845 {
2846   int n = mtext_nchars (mt);
2847
2848   mdraw_text_per_char_extents (frame, mt, 0, n, NULL, array_return, NULL,
2849                                n, &n, overall_return, NULL);
2850 }
2851
2852 /***en 
2853     @brief clear cached information.    
2854
2855     The mdraw_clear_cache () function clear cached information
2856     on M-text $MT that was attached by any of the drawing functions.
2857     When the behaviour of `format' or `line_break'
2858     member functions of MDrawControl is changed, the cache must be cleared.
2859
2860     @seealso
2861     MDrawControl */
2862 /***ja 
2863     @brief ¥­¥ã¥Ã¥·¥å¾ðÊó¤ò¾Ã¤¹.
2864
2865     ´Ø¿ô mdraw_clear_cache () ¤ÏÉÁ²è´Ø¿ô¤Ë¤è¤Ã¤Æ M-text $MT ¤ËÉÕ²Ã
2866     ¤µ¤ì¤¿¥­¥ã¥Ã¥·¥å¾ðÊó¤ò¤¹¤Ù¤Æ¾Ãµî¤¹¤ë¡£MDrawControl ¤Î `format' ¤¢
2867     ¤ë¤¤¤Ï `line_break' ¥á¥ó¥Ð´Ø¿ô¤Î¿¶Éñ¤¤¤¬ÊѤï¤Ã¤¿¾ì¹ç¤Ë¤Ï¥­¥ã¥Ã¥·¥å
2868     ¤ò¾Ãµî¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
2869     @seealso
2870     MDrawControl */
2871
2872 void
2873 mdraw_clear_cache (MText *mt)
2874 {
2875   mtext_pop_prop (mt, 0, mtext_nchars (mt), M_glyph_string);
2876 }
2877
2878 /*** @} */
2879
2880 /*
2881   Local Variables:
2882   coding: euc-japan
2883   End:
2884 */