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