(draw_background): Don't draw background even if
[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_VIDEOMODE] == Mreverse))
1019             {
1020               int this_x = x, this_width = width;
1021
1022               if (fromg->type == GLYPH_BOX)
1023                 this_x += fromg->width, this_width -= fromg->width;
1024               if (g[-1].type == GLYPH_BOX)
1025                 this_width -= g[-1].width;
1026               mwin__fill_space (frame, win, rface, 0,
1027                                 this_x, y - gstring->text_ascent, this_width,
1028                                 gstring->text_ascent + gstring->text_descent,
1029                                 control->clip_region);
1030             }
1031           if (cursor)
1032             {
1033               MDrawMetric rect;
1034             
1035               rect.x = cursor_x;
1036               rect.y = y - gstring->text_ascent;
1037               rect.height = gstring->text_ascent + gstring->text_descent;
1038               if (! cursor_bidi)
1039                 {
1040                   rect.width = ((control->cursor_width > 0
1041                                  && control->cursor_width < cursor_width)
1042                                 ? control->cursor_width : cursor_width);
1043                 }
1044               else
1045                 {
1046                   if (cursor->bidi_level % 2)
1047                     rect.x += cursor_width - 1;
1048                   rect.width = 1;
1049                 }
1050               mwin__fill_space (frame, win, rface, 1,
1051                                 rect.x, rect.y, rect.width, rect.height,
1052                                 control->clip_region);
1053               if (! region)
1054                 region = mwin__region_from_rect (&rect);
1055               else
1056                 mwin__region_add_rect (region, &rect);
1057               mwin__verify_region (frame, region);
1058               if (cursor_bidi)
1059                 {
1060                   if (cursor->bidi_level % 2)
1061                     rect.x -= 3;
1062                   rect.height = 2;
1063                   rect.width = cursor_width < 4 ? cursor_width : 4;
1064                   mwin__fill_space (frame, win, rface, 1,
1065                                     rect.x, rect.y, rect.width, rect.height,
1066                                     control->clip_region);
1067                   mwin__region_add_rect (region, &rect);
1068                   mwin__verify_region (frame, region);
1069                 }
1070             }
1071
1072           if (prev_pos >= 0)
1073             {
1074               int temp_width = 0;
1075
1076               cursor_width = 0;
1077               cursor = NULL;
1078               while (fromg < g)
1079                 {
1080                   if (fromg->type != GLYPH_BOX
1081                       && fromg->pos <= prev_pos && fromg->to > prev_pos)
1082                     {
1083                       if (! cursor)
1084                         cursor = fromg, cursor_x = x + temp_width;
1085                       cursor_width += fromg->width;
1086                     }
1087                   temp_width += fromg++->width;
1088                 }
1089               if (cursor)
1090                 {
1091                   MDrawMetric rect;
1092
1093                   rect.x = cursor_x;
1094                   if (! (cursor->bidi_level % 2))
1095                     rect.x += cursor_width - 1;
1096                   rect.y = y - gstring->text_ascent;
1097                   rect.height = gstring->text_ascent + gstring->text_descent;
1098                   rect.width = 1;
1099                   mwin__fill_space (frame, win, rface, 1,
1100                                     rect.x, rect.y, rect.width, rect.height,
1101                                     control->clip_region);
1102                   if (! region)
1103                     region = mwin__region_from_rect (&rect);
1104                   else
1105                     mwin__region_add_rect (region, &rect);
1106                   mwin__verify_region (frame, region);
1107                   rect.y += rect.height - 2;
1108                   rect.height = 2;
1109                   rect.width = cursor_width < 4 ? cursor_width : 4;
1110                   if (! (cursor->bidi_level % 2))
1111                     rect.x -= rect.width - 1;
1112                   mwin__fill_space (frame, win, rface, 1,
1113                                     rect.x, rect.y, rect.width, rect.height,
1114                                     control->clip_region);
1115                   mwin__region_add_rect (region, &rect);
1116                   mwin__verify_region (frame, region);
1117                 }
1118             }
1119           x += width;
1120           *to_idx = GLYPH_INDEX (g);
1121           *to_x = x;
1122         }
1123       else
1124         g++->enabled = 0;
1125     }
1126   return region;
1127 }
1128
1129 static void
1130 render_glyphs (MFrame *frame, MDrawWindow win, int x, int y, int width,
1131                MGlyphString *gstring, int from_idx, int to_idx,
1132                int reverse, MDrawRegion region)
1133 {
1134   MGlyph *g = MGLYPH (from_idx), *gend = MGLYPH (to_idx);
1135
1136   if (region)
1137     {
1138       MDrawMetric rect;
1139
1140       mwin__region_to_rect (region, &rect);
1141       if (rect.x > x)
1142         {
1143           while (g != gend && x + g->rbearing <= rect.x)
1144             {
1145               x += g->width;
1146               width -= g++->width;
1147               while (! g->enabled && g != gend)
1148                 g++;
1149             }
1150         }
1151       rect.x += rect.width;
1152       if (rect.x < x + width)
1153         {
1154           while (g != gend
1155                  && (x + width - gend[-1].width + gend[-1].lbearing >= rect.x))
1156             {
1157               width -= (--gend)->width;
1158               while (! gend->enabled && g != gend)
1159                 gend--;
1160             }
1161           if (g != gend)
1162             while (gend[-1].to == gend->to) gend++;
1163         }
1164     }
1165
1166   while (g != gend)
1167     {
1168       if (g->enabled)
1169         {
1170           MRealizedFace *rface = g->rface;
1171           int width = g->width;
1172           MGlyph *from_g = g++;
1173
1174           /* Handle the glyphs of the same type/face at once.  */
1175           while (g != gend
1176                  && g->type == from_g->type
1177                  && g->rface == rface
1178                  && (g->code < 0) == (from_g->code < 0)
1179                  && g->enabled)
1180             width += g++->width;
1181
1182           if (from_g->type == GLYPH_CHAR)
1183             {
1184               if (rface->rfont && from_g->code >= 0)
1185                 (rface->rfont->driver->render) (win, x, y, gstring, from_g, g,
1186                                                 reverse, region);
1187               else
1188                 mwin__draw_empty_boxes (win, x, y, gstring, from_g, g,
1189                                         reverse, region);
1190             }
1191           else if (from_g->type == GLYPH_BOX)
1192             {
1193               /* Draw the left or right side of a box.  If
1194                  from_g->lbearing is nonzero, this is the left side,
1195                  else this is the right side.  */
1196               mwin__draw_box (frame, win, gstring, from_g, x, y, 0, region);
1197             }
1198
1199           if (from_g->type != GLYPH_BOX)
1200             {
1201               if (rface->hline)
1202                 mwin__draw_hline (frame, win, gstring, rface, reverse,
1203                                   x, y, width, region);
1204               if (rface->box
1205                   && ! reverse)
1206                 /* Draw the top and bottom side of a box.  */
1207                    mwin__draw_box (frame, win, gstring, from_g,
1208                                    x, y, width, region);
1209             }
1210           x += width;
1211         }
1212       else
1213         g++;
1214     }
1215 }
1216
1217
1218 static int
1219 find_overlapping_glyphs (MGlyphString *gstring, int *left, int *right,
1220                          int *from_x, int *to_x)
1221 {
1222   MGlyph *g;
1223   int left_idx = *left, right_idx = *right;
1224   int left_x, right_x, x;
1225
1226   for (g = MGLYPH (*left) - 1, x = 0; g->type != GLYPH_ANCHOR; g--)
1227     {
1228       x -= g->width;
1229       if (x + g->rbearing > 0)
1230         {
1231           while (g[-1].pos == g->pos && g[-1].type != GLYPH_ANCHOR)
1232             x -= (--g)->width;
1233           left_idx = GLYPH_INDEX (g);
1234           left_x = x;
1235         }
1236     }
1237
1238   for (g = MGLYPH (*right), x = 0; g->type != GLYPH_ANCHOR; g++)
1239     {
1240       x += g->width;
1241       if (x - g->width + g->lbearing < 0)
1242         {
1243           while (g->pos == g[1].pos && g[1].type != GLYPH_ANCHOR)
1244             x += (++g)->width;
1245           right_idx = GLYPH_INDEX (g) + 1;
1246           right_x = x;
1247         }
1248     }
1249
1250   if (*left == left_idx && *right == right_idx)
1251     return 0;
1252
1253   if (*left != left_idx)
1254     {
1255       for (g = MGLYPH (*left) - 1; GLYPH_INDEX (g) >= left_idx; g--)
1256         g->enabled = 1;
1257       *left = left_idx;
1258       *from_x += left_x;
1259     }
1260   if (*right != right_idx)
1261     {
1262       for (g = MGLYPH (*right); GLYPH_INDEX (g) < right_idx; g++)
1263         g->enabled = 1;
1264       *right = right_idx;
1265       *to_x += right_x;
1266     }
1267   return 1;
1268 }
1269
1270
1271 static int
1272 gstring_width (MGlyphString *gstring, int from, int to, int *rbearing)
1273 {
1274   MGlyph *g;
1275   int width;
1276
1277   if (from <= gstring->from && to >= gstring->to)
1278     {
1279       if (rbearing)
1280         *rbearing = gstring->rbearing;
1281       return gstring->width;
1282     }
1283
1284   if (rbearing)
1285     *rbearing = 0;
1286   for (g = MGLYPH (1), width = 0; g->type != GLYPH_ANCHOR; g++)
1287     if (g->pos >= from && g->pos < to)
1288       {
1289         if (rbearing && width + g->rbearing > *rbearing)
1290           *rbearing = width + g->rbearing;
1291         width += g->width;
1292       }
1293   return width;
1294 }
1295
1296
1297 static void
1298 render_glyph_string (MFrame *frame, MDrawWindow win, int x, int y,
1299                      MGlyphString *gstring, int from, int to)
1300 {
1301   MDrawControl *control = &gstring->control;
1302   MDrawMetric rect;
1303   MDrawRegion clip_region, cursor_region;
1304   int from_idx, to_idx;
1305   int to_x;
1306
1307   if (control->orientation_reversed)
1308     x -= gstring->indent + gstring_width (gstring, from, to, NULL);
1309   else
1310     x += gstring->indent;
1311
1312   /* At first, draw all glyphs without cursor.  */
1313   cursor_region = draw_background (frame, win, x, y, gstring, from, to,
1314                                    &from_idx, &to_idx, &to_x);
1315
1316   if (control->partial_update)
1317     {
1318       rect.x = x;
1319       rect.width = to_x - x;
1320       if (find_overlapping_glyphs (gstring, &from_idx, &to_idx, &x, &to_x))
1321         {
1322           rect.y = y - gstring->line_ascent;
1323           rect.height = gstring->height;
1324           clip_region = mwin__region_from_rect (&rect);
1325           if (control->clip_region)
1326             mwin__intersect_region (clip_region, control->clip_region);
1327         }
1328       else
1329         clip_region = control->clip_region;
1330     }
1331   else
1332     clip_region = control->clip_region;
1333
1334   render_glyphs (frame, win, x, y, to_x - x, gstring, from_idx, to_idx,
1335                  0, clip_region);
1336   if (cursor_region)
1337     {
1338       if (clip_region)
1339         mwin__intersect_region (cursor_region, clip_region);
1340       render_glyphs (frame, win, x, y, to_x - x, gstring, from_idx, to_idx,
1341                      1, cursor_region);
1342     }
1343   if (clip_region != control->clip_region)
1344     mwin__free_region (clip_region);
1345   if (cursor_region)
1346     mwin__free_region (cursor_region);
1347   return;
1348 }
1349
1350 static int gstring_num;
1351
1352 static void
1353 free_gstring (void *object)
1354 {
1355   MGlyphString *gstring = (MGlyphString *) object;
1356
1357   if (gstring->next)
1358     free_gstring (gstring->next);
1359   if (gstring->size > 0)
1360     free (gstring->glyphs);
1361   free (gstring);
1362   gstring_num--;
1363 }
1364
1365
1366 static MGlyphString scratch_gstring;
1367
1368 static MGlyphString *
1369 alloc_gstring (MFrame *frame, MText *mt, int pos, MDrawControl *control,
1370                int line, int y)
1371 {
1372   MGlyphString *gstring;
1373
1374   if (pos == mt->nchars)
1375     {
1376       gstring = &scratch_gstring;
1377     }
1378   else
1379     {
1380       M17N_OBJECT (gstring, free_gstring, MERROR_DRAW);
1381       MLIST_INIT1 (gstring, glyphs, 128);
1382       gstring_num++;
1383     }
1384
1385   gstring->frame = frame;
1386   gstring->tick = frame->tick;
1387   gstring->top = gstring;
1388   gstring->mt = mt;
1389   gstring->control = *control;
1390   gstring->indent = gstring->width_limit = 0;
1391   if (control->format)
1392     (*control->format) (line, y, &(gstring->indent), &(gstring->width_limit));
1393   else
1394     gstring->width_limit = control->max_line_width;
1395   gstring->anti_alias = control->anti_alias;
1396   if (gstring->anti_alias
1397       && (unsigned) mwin__device_get_prop (frame->device, Mdepth) < 8)
1398     gstring->anti_alias = 0;
1399   return gstring;
1400 }
1401
1402 /* Truncate the line width of GSTRING to GSTRING->width_limit.  */
1403
1404 static void
1405 truncate_gstring (MFrame *frame, MText *mt, MGlyphString *gstring)
1406 {
1407   int width;
1408   int i;
1409   int *pos_width;
1410   MGlyph *g;
1411   int pos;
1412
1413   /* Setup the array POS_WIDTH so that POS_WIDTH[I - GSTRING->from] is
1414      a width of glyphs for the character at I of GSTRING->mt.  If I is
1415      not a beginning of a grapheme cluster, the corresponding element
1416      is 0.  */
1417   MTABLE_ALLOCA (pos_width, gstring->to - gstring->from, MERROR_DRAW);
1418   memset (pos_width, 0, sizeof (int) * (gstring->to - gstring->from));
1419   for (g = MGLYPH (1); g->type != GLYPH_ANCHOR; g++)
1420     pos_width[g->pos - gstring->from] += g->width;
1421   for (i = 0, width = 0; i < gstring->to - gstring->from; i++)
1422     {
1423       if (pos_width[i] > 0)
1424         {
1425           if (width + pos_width[i] > gstring->width_limit)
1426             break;
1427         }
1428       width += pos_width[i];
1429     }
1430
1431   pos = gstring->from + i;
1432   if (gstring->control.line_break)
1433     {
1434       pos = (*gstring->control.line_break) (gstring->mt, gstring->from + i,
1435                                             gstring->from, gstring->to, 0, 0);
1436       if (pos <= gstring->from || pos >= gstring->to)
1437         return;
1438     }
1439   compose_glyph_string (frame, mt, gstring->from, pos, gstring);
1440   layout_glyph_string (frame, gstring);
1441 }
1442
1443
1444 /* Return a gstring that covers a character at POS.  */
1445
1446 static MGlyphString *
1447 get_gstring (MFrame *frame, MText *mt, int pos, int to, MDrawControl *control)
1448 {
1449   MGlyphString *gstring = NULL;
1450
1451   if (pos < mtext_nchars (mt))
1452     {
1453       MTextProperty *prop = mtext_get_property (mt, pos, M_glyph_string);
1454
1455       if (prop
1456           && ((prop->start != 0
1457                && mtext_ref_char (mt, prop->start - 1) != '\n')
1458               || (prop->end < mtext_nchars (mt)
1459                   && mtext_ref_char (mt, prop->end - 1) != '\n')))
1460         {
1461           mtext_detach_property (prop);
1462           prop = NULL;
1463         }
1464       if (prop)
1465         {
1466           gstring = prop->val;
1467           if (gstring->frame != frame
1468               || gstring->tick != frame->tick
1469               || memcmp (control, &gstring->control,
1470                          (char *) (&control->with_cursor)
1471                          - (char *) (control)))
1472             {
1473               mtext_detach_property (prop);
1474               gstring = NULL;
1475             }
1476         }
1477     }
1478   else if (! control->cursor_width)
1479     return NULL;
1480
1481   if (gstring)
1482     {
1483       MGlyphString *gst;
1484       int offset;
1485
1486       offset = mtext_character (mt, pos, 0, '\n');
1487       if (offset < 0)
1488         offset = 0;
1489       else
1490         offset++;
1491       offset -= gstring->from;
1492       if (offset)
1493         for (gst = gstring; gst; gst = gst->next)
1494           {
1495             int i;
1496
1497             gst->from += offset;
1498             gst->to += offset;
1499             for (i = 0; i < gst->used; i++)
1500               {
1501                 gst->glyphs[i].pos += offset;
1502                 gst->glyphs[i].to += offset;
1503               }
1504           }
1505       M17N_OBJECT_REF (gstring);
1506     }
1507   else
1508     {
1509       int beg, end;
1510       int line = 0, y = 0;
1511
1512       if (control->two_dimensional)
1513         {
1514           beg = mtext_character (mt, pos, 0, '\n');
1515           if (beg < 0)
1516             beg = 0;
1517           else
1518             beg++;
1519           end = mtext_nchars (mt) + (control->cursor_width != 0);
1520         }
1521       else
1522         {
1523           beg = pos;
1524           end = to;
1525         }
1526       gstring = alloc_gstring (frame, mt, beg, control, line, y);
1527       compose_glyph_string (frame, mt, beg, end, gstring);
1528       layout_glyph_string (frame, gstring);
1529       end = gstring->to;
1530       if (control->two_dimensional
1531           && gstring->width_limit
1532           && gstring->width > gstring->width_limit)
1533         {
1534           MGlyphString *gst = gstring;
1535
1536           truncate_gstring (frame, mt, gst);
1537           while (gst->to < end)
1538             {
1539               line++, y += gst->height;
1540               gst->next = alloc_gstring (frame, mt, gst->from, control,
1541                                          line, y);
1542               gst->next->top = gstring;
1543               compose_glyph_string (frame, mt, gst->to, end, gst->next);
1544               gst = gst->next;
1545               layout_glyph_string (frame, gst);
1546               if (gst->width <= gst->width_limit)
1547                 break;
1548               truncate_gstring (frame, mt, gst);
1549             }
1550         }
1551
1552       if (! control->disable_caching && pos < mtext_nchars (mt))
1553         {
1554           MTextProperty *prop = mtext_property (M_glyph_string, gstring,
1555                                                 MTEXTPROP_VOLATILE_STRONG);
1556
1557           if (end > mtext_nchars (mt))
1558             end = mtext_nchars (mt);
1559           mtext_attach_property (mt, beg, end, prop);
1560           M17N_OBJECT_UNREF (prop);
1561         }
1562     }
1563
1564   while (gstring->to <= pos)
1565     {
1566       if (! gstring->next)
1567         mdebug_hook ();
1568       gstring = gstring->next;
1569     }
1570   gstring->control = *control;
1571
1572   return gstring;
1573 }
1574
1575
1576 static MDrawControl control_noop;
1577
1578 #define ASSURE_CONTROL(control) \
1579   if (! control)                \
1580     control = &control_noop;    \
1581   else
1582
1583
1584 static int
1585 draw_text (MFrame *frame, MDrawWindow win, int x, int y,
1586            MText *mt, int from, int to,
1587            MDrawControl *control)
1588 {
1589   MGlyphString *gstring;
1590
1591   M_CHECK_POS_X (mt, from, -1);
1592   ASSURE_CONTROL (control);
1593   if (to > mtext_nchars (mt) + (control->cursor_width != 0))
1594     to = mtext_nchars (mt) + (control->cursor_width != 0);
1595   else if (to < from)
1596     to = from;
1597
1598   gstring = get_gstring (frame, mt, from, to, control);
1599   if (! gstring)
1600     MERROR (MERROR_DRAW, -1);
1601   render_glyph_string (frame, win, x, y, gstring, from, to);
1602   from = gstring->to;
1603   while (from < to)
1604     {
1605       y += gstring->line_descent;
1606       M17N_OBJECT_UNREF (gstring->top);
1607       gstring = get_gstring (frame, mt, from, to, control);
1608       y += gstring->line_ascent;
1609       render_glyph_string (frame, win, x, y, gstring, from, to);
1610       from = gstring->to;
1611     }
1612   M17N_OBJECT_UNREF (gstring->top);
1613
1614   return 0;
1615 }
1616
1617
1618 static MGlyph *
1619 find_glyph_in_gstring (MGlyphString *gstring, int pos, int forwardp)
1620 {
1621   MGlyph *g;
1622
1623   if (forwardp)
1624     {
1625       for (g = MGLYPH (1); g->type != GLYPH_ANCHOR; g++)
1626         if (g->pos <= pos && g->to > pos)
1627           break;
1628     }
1629   else
1630     {
1631       for (g = MGLYPH (gstring->used - 2); g->type != GLYPH_ANCHOR; g--)
1632         if (g->pos <= pos && g->to > pos)
1633           break;
1634     }
1635   return g;
1636 }
1637
1638 \f
1639 /* for debugging... */
1640 char work[16];
1641
1642 char *
1643 dump_combining_code (int code)
1644 {
1645   char *vallign = "tcbB";
1646   char *hallign = "lcr";
1647   char *p;
1648   int off_x, off_y;
1649
1650   if (! code)
1651     return "none";
1652   if (COMBINING_BY_CLASS_P (code))
1653     code = combining_code_from_class (COMBINING_CODE_CLASS (code));
1654   work[0] = vallign[COMBINING_CODE_BASE_Y (code)];
1655   work[1] = hallign[COMBINING_CODE_BASE_X (code)];
1656   off_y = COMBINING_CODE_OFF_Y (code) - 128;
1657   off_x = COMBINING_CODE_OFF_X (code) - 128;
1658   if (off_y > 0)
1659     sprintf (work + 2, "+%d", off_y);
1660   else if (off_y < 0)
1661     sprintf (work + 2, "%d", off_y);
1662   else if (off_x == 0)
1663     sprintf (work + 2, ".");
1664   p = work + strlen (work);
1665   if (off_x > 0)
1666     sprintf (p, ">%d", off_x);
1667   else if (off_x < 0)
1668     sprintf (p, "<%d", -off_x);
1669   p += strlen (p);
1670   p[0] = vallign[COMBINING_CODE_ADD_Y (code)];
1671   p[1] = hallign[COMBINING_CODE_ADD_X (code)];
1672   p[2] = '\0';
1673   return work;
1674 }
1675
1676 void
1677 dump_gstring (MGlyphString *gstring, int indent)
1678 {
1679   char *prefix = (char *) alloca (indent + 1);
1680   MGlyph *g, *last_g = gstring->glyphs + gstring->used;
1681
1682   memset (prefix, 32, indent);
1683   prefix[indent] = 0;
1684
1685   fprintf (stderr, "(glyph-string");
1686
1687   for (g = MGLYPH (0); g < last_g; g++)
1688     fprintf (stderr,
1689              "\n%s  (%02d %s pos:%d-%d c:%04X code:%04X face:%x cmb:%s w:%02d bidi:%d)",
1690              prefix,
1691              g - gstring->glyphs,
1692              (g->type == GLYPH_SPACE ? "SPC": g->type == GLYPH_PAD ? "PAD"
1693               : g->type == GLYPH_ANCHOR ? "ANC"
1694               : g->type == GLYPH_BOX ? "BOX" : "CHR"),
1695              g->pos, g->to, g->c, g->code, (unsigned) g->rface,
1696              dump_combining_code (g->combining_code),
1697              g->width, g->bidi_level);
1698   fprintf (stderr, ")");
1699 }
1700 \f
1701
1702 /* m17n-X internal APIs */
1703
1704 int
1705 mdraw__init ()
1706 {
1707   M_glyph_string = msymbol_as_managing_key ("  glyph-string");
1708
1709   memset (&scratch_gstring, 0, sizeof (scratch_gstring));
1710   MLIST_INIT1 (&scratch_gstring, glyphs, 3);
1711
1712   Mlatin = msymbol ("latin");
1713   Minherited = msymbol ("inherited");
1714
1715   McatCc = msymbol ("Cc");
1716   McatCf = msymbol ("Cf");
1717   Mdepth = msymbol ("depth");
1718
1719   MbidiR = msymbol ("R");
1720   MbidiAL = msymbol ("AL");
1721   MbidiRLE = msymbol ("RLE");
1722   MbidiRLO = msymbol ("RLO");
1723   MbidiBN = msymbol ("BN");
1724   MbidiS = msymbol ("S");
1725 #ifdef HAVE_FRIBIDI
1726   fribidi_set_mirroring (TRUE);
1727 #endif
1728
1729   return 0;
1730 }
1731
1732 void
1733 mdraw__fini ()
1734 {
1735   MLIST_FREE1 (&scratch_gstring, glyphs);
1736 }
1737
1738 /*** @} */
1739 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
1740
1741 \f
1742 /* External API */
1743 /*** @addtogroup m17nDraw */
1744 /*** @{ */
1745
1746 /*=*/
1747 /***en
1748     @brief Draw an M-text on a window.
1749
1750     The mdraw_text () function draws the text between $FROM and $TO of
1751     M-text $MT on window $WIN of frame $FRAME at coordinate ($X, $Y).
1752
1753     The appearance of the text (size, style, color, etc) is specified
1754     by the value of the text property whose key is @c Mface.  If the
1755     M-text or a part of the M-text does not have such a text property,
1756     the default face of $FRAME is used.
1757
1758     The font used to draw a character in the M-text is selected from
1759     the value of the fontset property of a face by the following
1760     algorithm:
1761
1762     <ol>
1763
1764     <li> Search the text properties given to the character for the one
1765          whose key is @c Mcharset; its value should be either a symbol
1766          specifying a charset or #Mnil.  If the value is #Mnil,
1767          proceed to the next step.
1768
1769          Otherwise, search the mapping table of the fontset for the
1770          charset.  If no entry is found proceed to the next step.  
1771
1772          If an entry is found, use one of the fonts in the entry that
1773          has a glyph for the character and that matches best with the
1774          face properties.  If no such font exists, proceed to the next
1775          step.
1776
1777     <li> Get the character property "script" of the character.  If it is
1778          inherited, get the script property from the previous
1779          characters.  If there is no previous character, or none of
1780          them has the script property other than inherited, proceed to
1781          the next step.
1782
1783          Search the text properties given to the character for the one
1784          whose key is @c Mlanguage; its value should be either a
1785          symbol specifying a language or @c Mnil.
1786
1787          Search the mapping table of the fontset for the combination
1788          of the script and language.  If no entry is found, proceed to
1789          the next step.  
1790
1791         If an entry is found, use one of the fonts in the entry that
1792          has a glyph for the character and that matches best with the
1793          face properties.  If no such font exists, proceed to the next
1794          step.
1795
1796     <li> Search the fall-back table of the fontset for a font that has
1797          a glyph of the character.  If such a font is found, use that
1798          font.
1799
1800     </ol>
1801
1802     If no font is found by the algorithm above, this function draws an
1803     empty box for the character.
1804
1805     This function draws only the glyph foreground.  To specify the
1806     background color, use mdraw_image_text () or
1807     mdraw_text_with_control ().
1808
1809     This function is the counterpart of <tt>XDrawString ()</tt>,
1810     <tt>XmbDrawString ()</tt>, and <tt>XwcDrawString ()</tt> functions
1811     in the X Window System.
1812
1813     @return
1814     If the operation was successful, mdraw_text () returns 0.  If an
1815     error is detected, it returns -1 and assigns an error code to the
1816     external variable #merror_code.  */
1817 /***ja
1818     @brief ¥¦¥£¥ó¥É¥¦¤Ë M-text ¤òÉÁ²è¤¹¤ë.
1819
1820     ´Ø¿ô mdraw_text () ¤Ï¡¢¥Õ¥ì¡¼¥à $FRAME ¤Î¥¦¥£¥ó¥É¥¦ $WIN ¤ÎºÂɸ 
1821     ($X, $Y) ¤Ë¡¢M-text $MT ¤Î $FROM ¤«¤é $TO ¤Þ¤Ç¤Î¥Æ¥­¥¹¥È¤ò
1822     ÉÁ²è¤¹¤ë¡£
1823
1824     ¥Æ¥­¥¹¥È¤Î¸«±É¤¨¡Ê¥Õ¥©¥ó¥È¡¢¥¹¥¿¥¤¥ë¡¢¿§¤Ê¤É¡Ë¤Ï¡¢¥­¡¼¤¬ @c Mface 
1825     ¤Ç¤¢¤ë¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤ÎÃͤˤè¤Ã¤Æ·è¤Þ¤ë¡£M-text ¤Î°ìÉô¤¢¤ë¤¤¤Ï
1826     Á´Éô¤Ë¤½¤Î¤è¤¦¤Ê¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤¬ÉÕ¤¤¤Æ¤¤¤Ê¤¤¾ì¹ç¤Ë¤Ï¡¢$FRAME 
1827     ¤Î¥Ç¥Õ¥©¥ë¥È¥Õ¥§¡¼¥¹¤¬ÍѤ¤¤é¤ì¤ë¡£
1828
1829     M-text ¤Î³Æʸ»ú¤òɽ¼¨¤¹¤ë¥Õ¥©¥ó¥È¤Ï¡¢¥Õ¥§¡¼¥¹¤Î fontset ¥×¥í¥Ñ¥Æ¥£
1830     ¤ÎÃͤ«¤é°Ê²¼¤Î¥¢¥ë¥´¥ê¥º¥à¤ÇÁª¤Ð¤ì¤ë¡£
1831
1832     <ol>
1833
1834     <li> ¤½¤Îʸ»ú¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Î¤¦¤Á¡¢¥­¡¼¤¬ @c Mcharset ¤Ç¤¢¤ë
1835          ¤â¤Î¤ÎÃͤòÄ´¤Ù¤ë¡£¤³¤ÎÃͤÏʸ»ú¥»¥Ã¥È¤òɽ¤ï¤¹¥·¥ó¥Ü¥ë¤« #Mnil 
1836          ¤Î¤É¤Á¤é¤«¤Ç¤¢¤ë¡£#Mnil ¤Ê¤é¤Ð¡¢¼¡¤Î¥¹¥Æ¥Ã¥×¤Ë¿Ê¤à¡£¤½¤¦¤Ç¤Ê
1837          ¤±¤ì¤Ð¡¢¤½¤Î¥Õ¥©¥ó¥È¥»¥Ã¥È¤Î¥Þ¥Ã¥Ô¥ó¥°¥Æ¡¼¥Ö¥ë¤«¤é¤½¤Îʸ»ú¥»¥Ã
1838          ¥ÈÍѤΤâ¤Î¤òõ¤¹¡£¥Õ¥©¥ó¥È¤¬¤ß¤Ä¤«¤é¤Ê¤±¤ì¤Ð¡¢¼¡¤Î¥¹¥Æ¥Ã¥×¤Ë
1839          ¿Ê¤à¡£
1840          
1841          ¤½¤Îʸ»ú¥»¥Ã¥ÈÍѤΥե©¥ó¥È¤¬¤ß¤Ä¤«¤ì¤Ð¡¢¤½¤ì¤é¤Î¤¦¤Á¸½ºß¤Îʸ
1842          »úÍѤΥ°¥ê¥Õ¤ò»ý¤Á¡¢¥Õ¥§¡¼¥¹¤Î³Æ¥×¥í¥Ñ¥Æ¥£¤ËºÇ¤â¤è¤¯¹çÃפ·¤Æ
1843          ¤¤¤ë¤â¤Î¤ò»È¤¦¡£¤½¤Î¤è¤¦¤Ê¥Õ¥©¥ó¥È¤¬Ìµ¤±¤ì¤Ð¼¡¤Î¥¹¥Æ¥Ã¥×¤Ë¿Ê
1844          ¤à¡£
1845
1846     <li> ¤½¤Îʸ»ú¤Îʸ»ú¥×¥í¥Ñ¥Æ¥£ "script" ¡Ê¥¹¥¯¥ê¥×¥È¡Ë¤òÄ´¤Ù¤ë¡£·Ñ
1847          ¾µ¤µ¤ì¤Æ¤¤¤ë¤Ê¤é¤Ð¤½¤ì°ÊÁ°¤Îʸ»ú¤Îʸ»ú¥×¥í¥Ñ¥Æ¥£ "script" ¤ò
1848          Ä´¤Ù¤ë¡£Á°¤Îʸ»ú¤¬¤Ê¤«¤Ã¤¿¤ê¡¢¤½¤Îʸ»ú¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Ã¤Æ¤¤¤Ê
1849          ¤«¤Ã¤¿¾ì¹ç¤Ë¤Ï¡¢¼¡¤Î¥¹¥Æ¥Ã¥×¤Ë¿Ê¤à¡£
1850
1851          ¤½¤Îʸ»ú¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Î¤¦¤Á¡¢¥­¡¼¤¬ @c Mlanguage ¤Ç¤¢
1852          ¤ë¤â¤Î¤ÎÃͤòÄ´¤Ù¤ë¡£¤³¤ÎÃͤϸÀ¸ì¤òɽ¤ï¤¹¥·¥ó¥Ü¥ë¤« @c Mnil ¤Î
1853          ¤¤¤º¤ì¤«¤Ç¤¢¤ë¡£
1854
1855          ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢¤½¤Î¸À¸ì¤È¥¹¥¯¥ê¥×¥È¤ÎÁȤ߹ç¤ï¤»ÍѤΥե©¥ó¥È
1856          ¥»¥Ã¥È¤ò¥Þ¥Ã¥Ô¥ó¥°¥Æ¡¼¥Ö¥ë¤«¤éõ¤¹¡£¸«¤Ä¤«¤é¤Ê¤±¤ì¤Ð¼¡¤Î¥¹¥Æ¥Ã
1857          ¥×¤Ë¿Ê¤à¡£
1858
1859          ¤½¤Î¤è¤¦¤Êʸ»ú¥»¥Ã¥ÈÍѤΥե©¥ó¥È¤¬¤ß¤Ä¤«¤ì¤Ð¡¢¤½¤ì¤é¤Î¤¦¤Á¸½
1860          ºß¤Îʸ»úÍѤΥ°¥ê¥Õ¤ò»ý¤Á¡¢¥Õ¥§¡¼¥¹¤Î³Æ¥×¥í¥Ñ¥Æ¥£¤ËºÇ¤â¤è¤¯¹ç
1861          Ãפ·¤Æ¤¤¤ë¤â¤Î¤ò»È¤¦¡£¤½¤Î¤è¤¦¤Ê¥Õ¥©¥ó¥È¤¬Ìµ¤±¤ì¤Ð¼¡¤Î¥¹¥Æ¥Ã
1862          ¥×¤Ë¿Ê¤à¡£
1863
1864     <li> ¤½¤Îʸ»ú¤Î¥°¥ê¥Õ¤ò»ý¤Ä¥Õ¥©¥ó¥È¤ò¡¢¥Õ¥©¥ó¥È¥»¥Ã¥È¤Îfall-back¥Æ¡¼
1865          ¥Ö¥ë¤«¤éõ¤¹¡£¥Õ¥©¥ó¥È¤¬¸«¤Ä¤«¤ì¤Ð¤½¤ì¤ò»È¤¦¡£
1866
1867     </ol>
1868
1869     °Ê¾å¤Î¥¢¥ë¥´¥ê¥º¥à¤Ç¥Õ¥©¥ó¥È¤¬¸«¤Ä¤«¤é¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï¤½¤Îʸ»ú
1870     ¤È¤·¤Æ¶õ¤Î»Í³Ñ·Á¤òɽ¼¨¤¹¤ë¡£
1871
1872     ¤³¤Î´Ø¿ô¤¬ÉÁ²è¤¹¤ë¤Î¤Ï¥°¥ê¥Õ¤ÎÁ°·Ê¤À¤±¤Ç¤¢¤ë¡£ÇØ·Ê¿§¤ò»ØÄꤹ¤ë¤Ë¤Ï¡¢
1873     ´Ø¿ô mdraw_image_text () ¤«´Ø¿ô mdraw_text_with_control () ¤ò»È¤¦
1874     ¤³¤È¡£
1875
1876     ¤³¤Î´Ø¿ô¤Ï¡¢X ¥¦¥£¥ó¥É¥¦¤Ë¤ª¤±¤ë´Ø¿ô <tt>XDrawString ()</tt>,
1877     <tt>XmbDrawString ()</tt>, <tt>XwcDrawString ()</tt> ¤ËÁêÅö¤¹¤ë¡£
1878
1879     @return
1880     ½èÍý¤¬À®¸ù¤·¤¿¾ì¹ç¡¢mdraw_text () ¤Ï 0 ÊÖ¤¹¡£¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì¤¿¾ì
1881     ¹ç¤Ï -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
1882
1883     @latexonly \IPAlabel{mdraw_text} @endlatexonly  */
1884
1885 /***
1886     @errors
1887     @c MERROR_RANGE
1888
1889     @seealso
1890     mdraw_image_text ()  */
1891
1892 int
1893 mdraw_text (MFrame *frame, MDrawWindow win, int x, int y,
1894             MText *mt, int from, int to)
1895 {
1896   MDrawControl control;
1897
1898   memset (&control, 0, sizeof control);
1899   control.as_image = 0;
1900   return draw_text (frame, win, x, y, mt, from, to, &control);
1901 }
1902
1903 /*=*/
1904
1905
1906 /***en
1907     @brief Draw an M-text on a window as an image.
1908
1909     The mdraw_image_text () function draws the text between $FROM and
1910     $TO of M-text $MT as image on window $WIN of frame $FRAME at
1911     coordinate ($X, $Y).
1912
1913     The way to draw a text is the same as in mdraw_text () except that
1914     this function also draws the background with the color specified
1915     by faces.
1916
1917     This function is the counterpart of <tt>XDrawImageString ()</tt>,
1918     <tt>XmbDrawImageString ()</tt>, and <tt>XwcDrawImageString ()</tt>
1919     functions in the X Window System.
1920
1921     @return
1922     If the operation was successful, mdraw_image_text () returns 0.
1923     If an error is detected, it returns -1 and assigns an error code
1924     to the external variable #merror_code.  */
1925
1926 /***ja
1927     @brief ¥Ç¥£¥¹¥×¥ì¥¤¤ËM-text ¤ò²èÁü¤È¤·¤ÆÉÁ¤¯.
1928   
1929     ´Ø¿ô mdraw_image_text () ¤Ï¡¢¥Õ¥ì¡¼¥à $FRAME ¤Î¥¦¥£¥ó¥É¥¦ $WIN ¤Î
1930     ºÂɸ ($X, $Y) ¤Ë¡¢M-text $MT ¤Î $FROM ¤«¤é $TO ¤Þ¤Ç¤Î¥Æ¥­¥¹¥È¤ò²è
1931     Áü¤È¤·¤ÆÉÁ¤¯¡£
1932
1933     ¥Æ¥­¥¹¥È¤ÎÉÁ²èÊýË¡¤Ï mdraw_text () ¤È¤Û¤ÜƱ¤¸¤Ç¤¢¤ë¤¬¡¢¤³¤Î´Ø¿ô¤Ç
1934     ¤Ï¥Õ¥§¡¼¥¹¤Ç»ØÄꤵ¤ì¤¿¿§¤ÇÇطʤâÉÁ¤¯ÅÀ¤¬°Û¤Ê¤Ã¤Æ¤¤¤ë¡£
1935
1936     ¤³¤Î´Ø¿ô¤Ï¡¢X ¥¦¥£¥ó¥É¥¦¤Ë¤ª¤±¤ë <tt>XDrawImageString ()</tt>,
1937     <tt>XmbDrawImageString ()</tt>, <tt>XwcDrawImageString ()</tt> ¤Ë
1938     ÁêÅö¤¹¤ë¡£
1939
1940     @return
1941     ½èÍý¤¬À®¸ù¤·¤¿¾ì¹ç¡¢mdraw_image_text () ¤Ï 0 ¤òÊÖ¤¹¡£¥¨¥é¡¼¤¬¸¡½Ð
1942     ¤µ¤ì¤¿¾ì¹ç¤Ï -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #m_errro ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ
1943     ¤ë¡£
1944
1945     @latexonly \IPAlabel{mdraw_image_text} @endlatexonly   */
1946
1947 /***
1948     @errors
1949     @c MERROR_RANGE
1950
1951     @seealso
1952     mdraw_text ()  */
1953
1954 int
1955 mdraw_image_text (MFrame *frame, MDrawWindow win, int x, int y,
1956                   MText *mt, int from, int to)
1957 {
1958   MDrawControl control;
1959
1960   memset (&control, 0, sizeof control);
1961   control.as_image = 1;
1962   return draw_text (frame, win, x, y, mt, from, to, &control);
1963 }
1964
1965 /*=*/
1966
1967 /***en
1968     @brief Draw an M-text on a window with fine control.
1969
1970     The mdraw_text_with_control () function draws the text between
1971     $FROM and $TO of M-text $MT on windows $WIN of frame $FRAME at
1972     coordinate ($X, $Y).
1973
1974     The way to draw a text is the same as in mdraw_text () except that
1975     this function also follows what specified in the drawing control
1976     object $CONTROL.
1977
1978     For instance, if <two_dimensional> of $CONTROL is nonzero, this
1979     function draw an M-text 2-dimensionally, i.e., newlines in M-text
1980     breaks lines and the following characters are drawn in the next
1981     line.  See the documentation of the structure @ MDrawControl for
1982     more detail.  */
1983
1984 /***ja
1985     @brief ¥Ç¥£¥¹¥×¥ì¥¤¤ËM-text ¤òÉÁ¤¯¡Ê¾ÜºÙ¤ÊÀ©¸æ¤Ä¤­¡Ë.
1986
1987     ´Ø¿ô mdraw_text_with_control () ¤Ï¡¢¥Õ¥ì¡¼¥à $FRAME ¤Î¥¦¥£¥ó¥É¥¦ 
1988     $WIN ¤ÎºÂɸ ($X, $Y) ¤Ë¡¢M-text $MT ¤Î $FROM ¤«¤é $TO ¤Þ¤Ç¤Î¥Æ¥­¥¹
1989     ¥È¤òÉÁ¤¯¡£
1990
1991     ¥Æ¥­¥¹¥È¤ÎÉÁ²èÊýË¡¤Ï mdraw_text () ¤È¤Û¤ÜƱ¤¸¤Ç¤¢¤ë¤¬¡¢¤³¤Î´Ø¿ô¤Ï
1992     ÉÁ²èÀ©¸æÍѤΥª¥Ö¥¸¥§¥¯¥È $CONTROL ¤Ç¤Î»Ø¼¨¤Ë¤â½¾¤¦ÅÀ¤¬°Û¤Ê¤Ã¤Æ¤¤¤ë¡£
1993
1994     ¤¿¤È¤¨¤Ð $CONTROL ¤Î <two_dimensional> ¤¬¥¼¥í¤Ç¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô
1995     ¤ÏM-text ¤ò2¼¡¸µÅª¤ËÉÁ¤¯¡£¤¹¤Ê¤ï¤Á M-text Ãæ¤Î²þ¹Ô¤Ç¹Ô¤ò²þ¤á¡¢Â³¤¯
1996     Ê¸»ú¤Ï¼¡¤Î¹Ô¤ËÉÁ¤¯¡£¾ÜºÙ¤Ï¹½Â¤ÂΠ@ MDrawControl ¤ÎÀâÌÀ¤ò»²¾È¤¹¤ë¤³
1997     ¤È¡£*/
1998
1999 int
2000 mdraw_text_with_control (MFrame *frame, MDrawWindow win, int x, int y,
2001                          MText *mt, int from, int to, MDrawControl *control)
2002 {
2003   return draw_text (frame, win, x, y, mt, from, to, control);
2004 }
2005
2006 /*=*/
2007
2008 /***en
2009     @brief Compute text pixel width.
2010
2011     The mdraw_text_extents () function computes the width of text
2012     between $FROM and $TO of M-text $MT when it is drawn on a window
2013     of frame $FRAME using the mdraw_text_with_control () function with
2014     the drawing control object $CONTROL.
2015
2016     If $OVERALL_INK_RETURN is not @c NULL, this function also computes
2017     the bounding box of character ink of the M-text, and stores the
2018     results in the members of the structure pointed to by
2019     $OVERALL_INK_RETURN.  If the M-text has a face specifying a
2020     surrounding box, the box is included in the bounding box.
2021
2022     If $OVERALL_LOGICAL_RETURN is not @c NULL, this function also
2023     computes the bounding box that provides mininum spacing to other
2024     graphical features (such as surrounding box) for the M-text, and
2025     stores the results in the members of the structure pointed to by
2026     $OVERALL_LOGICAL_RETURN.
2027
2028     If $OVERALL_LINE_RETURN is not @c NULL, this function also
2029     computes the bounding box that provides mininum spacing to the
2030     other M-text drawn, and stores the results in the members of the
2031     structure pointed to by $OVERALL_LINE_RETURN.  This is a union of
2032     $OVERALL_INK_RETURN and $OVERALL_LOGICAL_RETURN if the members
2033     min_line_ascent, min_line_descent, max_line_ascent, and
2034     max_line_descent of $CONTROL are all zero.
2035
2036     @return
2037     This function returns the width of the text to be drawn in the
2038     unit of pixels.  If $CONTROL->two_dimensional is nonzero and the
2039     text is drawn in multiple physical lines, it returns the width of
2040     the widest line.  If an error occurs, it returns -1 and assigns an
2041     error code to the external variable #merror_code.  */
2042
2043
2044 /***ja 
2045     @brief ¥Æ¥­¥¹¥È¤ÎÉý¡Ê¥Ô¥¯¥»¥ëñ°Ì¡Ë¤ò·×»»¤¹¤ë.
2046
2047     ´Ø¿ô mdraw_text_extents () ¤Ï¡¢´Ø¿ô mdraw_text_with_control () ¤¬
2048     ÉÁ²èÀ©¸æ¥ª¥Ö¥¸¥§¥¯¥È $CONTROL ¤òÍѤ¤¤Æ M-text $MT ¤Î $FROM ¤«¤é $TO 
2049     ¤Þ¤Ç¤ò¥Õ¥ì¡¼¥à $FRAME ¤Ëɽ¼¨¤¹¤ëºÝ¤ËɬÍפȤʤëÉý¤òÊÖ¤¹¡£
2050
2051     $OVERALL_INK_RETURN ¤¬ @c NULL ¤Ç¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï M-text ¤Îʸ
2052     »ú¤Î¥¤¥ó¥¯¤Î¥Ð¥¦¥ó¥Ç¥£¥ó¥°¥Ü¥Ã¥¯¥¹¤â·×»»¤·¡¢$OVERALL_INK_RETURN ¤¬
2053     »Ø¤¹¹½Â¤ÂΤΥá¥ó¥Ð¤Ë¤½¤Î·ë²Ì¤òÀßÄꤹ¤ë¡£M-text ¤Ë°Ï¤ßÏÈ(surrounding box)
2054     ¤ò»ØÄꤹ¤ë¥Õ¥§¡¼¥¹¤¬¤¢¤ì¤Ð¡¢¤½¤ì¤â¥Ð¥¦¥ó¥Ç¥£¥ó¥°¥Ü¥Ã¥¯¥¹¤Ë´Þ¤à¡£
2055
2056     $OVERALL_LOGICAL_RETURN ¤¬ @c NULL ¤Ç¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï M-text 
2057     ¤È¾¤Î graphical feature ¡Ê°Ï¤ßÏȤʤɡˤȤδ֤κǾ®¤Î¥¹¥Ú¡¼¥¹¤ò¼¨
2058     ¤¹¥Ð¥¦¥ó¥Ç¥£¥ó¥°¥Ü¥Ã¥¯¥¹¤â·×»»¤·¡¢$OVERALL_LOGICAL_RETURN ¤¬»Ø¤¹¹½
2059     Â¤ÂΤΥá¥ó¥Ð¤Ë¤½¤Î·ë²Ì¤òÀßÄꤹ¤ë¡£
2060
2061     $OVERALL_LINE_RETURN ¤¬ @c NULL ¤Ç¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï¾¤Î M-text 
2062     ¤È¤Î´Ö¤ÎºÇ¾®¤Î¥¹¥Ú¡¼¥¹¤ò¼¨¤¹¥Ð¥¦¥ó¥Ç¥£¥ó¥°¥Ü¥Ã¥¯¥¹¤â·×»»¤·¡¢
2063     $OVERALL_LINE_RETURN ¤¬»Ø¤¹¹½Â¤ÂΤΥá¥ó¥Ð¤Ë¤½¤Î·ë²Ì¤òÀßÄꤹ¤ë¡£¥ª
2064     ¥Ö¥¸¥§¥¯¥È $CONTROL ¤Î¥á¥ó¥Ð min_line_ascent, min_line_descent,
2065     max_line_ascent, max_line_descent ¤¬¤¹¤Ù¤Æ0¤Î»þ¤Ë¤Ï¡¢¤³¤ÎÃͤϠ
2066     $OVERALL_INK_RETURN ¤È$OVERALL_LOGICAL_RETURN ¤ÎϤȤʤ롣
2067
2068     @return ¤³¤Î´Ø¿ô¤Ïɽ¼¨¤ËɬÍפʥƥ­¥¹¥È¤ÎÉý¤ò¥Ô¥¯¥»¥ëñ°Ì¤ÇÊÖ¤¹¡£
2069     $CONTROL->two_dimensional ¤¬0¤Ç¤Ê¤¯¡¢¥Æ¥­¥¹¥È¤¬Ê£¿ô¤Î¹Ô¤ËÅϤäÆÉÁ
2070     ¤«¤ì¤ë¾ì¹ç¤Ë¤Ï¡¢ºÇÂç¤ÎÉý¤òÊÖ¤¹¡£¥¨¥é¡¼¤¬À¸¤¸¤¿¾ì¹ç¤Ï -1 ¤òÊÖ¤·¡¢³°
2071     ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
2072
2073     @latexonly \IPAlabel{mdraw_text_extents} @endlatexonly  */
2074
2075 /***
2076     @errors
2077     @c MERROR_RANGE  */
2078
2079 int
2080 mdraw_text_extents (MFrame *frame,
2081                     MText *mt, int from, int to, MDrawControl *control,
2082                     MDrawMetric *overall_ink_return,
2083                     MDrawMetric *overall_logical_return,
2084                     MDrawMetric *overall_line_return)
2085 {
2086   MGlyphString *gstring;
2087   int y = 0;
2088   int width, rbearing;
2089
2090   ASSURE_CONTROL (control);
2091   M_CHECK_POS_X (mt, from, -1);
2092   if (to > mtext_nchars (mt) + (control->cursor_width != 0))
2093     to = mtext_nchars (mt) + (control->cursor_width != 0);
2094   else if (to < from)
2095     to = from;
2096
2097   gstring = get_gstring (frame, mt, from, to, control);
2098   if (! gstring)
2099     MERROR (MERROR_DRAW, -1);
2100   width = gstring_width (gstring, from, to, &rbearing);
2101   if (overall_ink_return)
2102     {
2103       overall_ink_return->y = - gstring->physical_ascent;
2104       overall_ink_return->x = gstring->lbearing;
2105     }
2106   if (overall_logical_return)
2107     {
2108       overall_logical_return->y = - gstring->ascent;
2109       overall_logical_return->x = 0;
2110     }
2111   if (overall_line_return)
2112     {
2113       overall_line_return->y = - gstring->line_ascent;
2114       overall_line_return->x = gstring->lbearing;
2115     }
2116
2117   for (from = gstring->to; from < to; from = gstring->to)
2118     {
2119       int this_width, this_rbearing;
2120
2121       y += gstring->line_descent;
2122       M17N_OBJECT_UNREF (gstring->top);
2123       gstring = get_gstring (frame, mt, from, to, control);
2124       this_width = gstring_width (gstring, from, to, &this_rbearing);
2125       y += gstring->line_ascent;
2126       if (width < this_width)
2127         width = this_width;
2128       if (rbearing < this_rbearing)
2129         rbearing = this_rbearing;
2130     }
2131   if (overall_ink_return)
2132     {
2133       overall_ink_return->width = rbearing;
2134       overall_ink_return->height
2135         = y + gstring->physical_descent - overall_ink_return->y;
2136     }
2137   if (overall_logical_return)
2138     {
2139       overall_logical_return->width = width;
2140       overall_logical_return->height
2141         = y + gstring->descent - overall_logical_return->y;
2142     }
2143   if (overall_line_return)
2144     {
2145       overall_line_return->width = MAX (width, rbearing);
2146       overall_line_return->height
2147         = y + gstring->line_descent - overall_line_return->y;
2148     }
2149
2150   M17N_OBJECT_UNREF (gstring->top);
2151   return width;
2152 }
2153
2154 /*=*/
2155
2156 /***en
2157     @brief Compute the text dimensions of each character of M-text.
2158
2159     The mdraw_text_per_char_extents () function computes the drawn
2160     metric of each character between $FROM and $TO of M-text $MT
2161     assuming that they are drawn on a window of frame $FRAME using the
2162     mdraw_text_with_control () function with the drawing control
2163     object $CONTROL.
2164
2165     $ARRAY_SIZE specifies the size of $INK_ARRAY_RETURN and
2166     $LOGICAL_ARRAY_RETURN.  Each successive element of
2167     $INK_ARRAY_RETURN and $LOGICAL_ARRAY_RETURN are set to the drawn
2168     ink and logical metrics of successive characters respectively,
2169     relative to the drawing origin of the M-text.  The number of
2170     elements of $INK_ARRAY_RETURN and $LOGICAL_ARRAY_RETURN that have
2171     been set is returned to $NUM_CHARS_RETURN.
2172
2173     If $ARRAY_SIZE is too small to return all metrics, the function
2174     returns -1 and store the requested size in $NUM_CHARS_RETURN.
2175     Otherwise, it returns zero.
2176
2177     If pointer $OVERALL_INK_RETURN and $OVERALL_LOGICAL_RETURN are not
2178     @c NULL, this function also computes the metrics of the overall
2179     text and stores the results in the members of the structure
2180     pointed to by $OVERALL_INK_RETURN and $OVERALL_LOGICAL_RETURN.
2181
2182     If $CONTROL->two_dimensional is nonzero, this function computes
2183     only the metrics of characters in the first line.  */
2184 /***ja
2185     @brief  M-text ¤Î³Æʸ»ú¤Îɽ¼¨ÈϰϤò·×»»¤¹¤ë.
2186
2187     ´Ø¿ô mdraw_text_per_char_extents () ¤Ï¡¢´Ø¿ô 
2188     mdraw_text_with_control () ¤¬ÉÁ²èÀ©¸æ¥ª¥Ö¥¸¥§¥¯¥È $CONTROL ¤òÍѤ¤
2189     ¤Æ M-text $MT ¤Î $FROM ¤«¤é $TO ¤Þ¤Ç¤ò¥Õ¥ì¡¼¥à $FRAME ¤Ëɽ¼¨¤¹¤ëºÝ
2190     ¤Î³Æʸ»ú¤Î¥µ¥¤¥º¤ò·×»»¤¹¤ë¡£
2191
2192     $ARRAY_SIZE ¤Ë¤è¤Ã¤Æ $INK_ARRAY_RETURN ¤È$LOGICAL_ARRAY_RETURN ¤Î
2193     ¥µ¥¤¥º¤ò»ØÄꤹ¤ë¡£$INK_ARRAY_RETURN ¤È$LOGICAL_ARRAY_RETURN ¤Î³ÆÍ×
2194     ÁǤϡ¢¤½¤ì¤¾¤ìʸ»ú¤ÎÉÁ²è¥¤¥ó¥¯¤ÈÏÀÍý¥µ¥¤¥º¡ÊM-text¤Îɽ¼¨¸¶ÅÀ¤«¤é¤Î
2195     ÁêÂаÌÃ͡ˤˤè¤Ã¤Æ½ç¤ËËä¤á¤é¤ì¤ë¡£ÀßÄꤵ¤ì¤¿ $INK_ARRAY_RETURN ¤È 
2196     $LOGICAL_ARRAY_RETURN ¤ÎÍ×ÁǤοô¤Ï¡¢$NUM_CHARS_RETURN ¤ËÌᤵ¤ì¤ë¡£
2197    
2198     $ARRAY_SIZE ¤¬¤¹¤Ù¤Æ¤ÎÀ£Ë¡¤òÌ᤻¤Ê¤¤¤Û¤É¾®¤µ¤¤¾ì¹ç¤Ë¤Ï¡¢´Ø¿ô¤Ï -1 
2199     ¤òÊÖ¤·¡¢É¬ÍפÊÂ礭¤µ¤ò $NUM_CHARS_RETURN ¤ËÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð 0 
2200     ¤òÊÖ¤¹¡£
2201
2202     ¥Ý¥¤¥ó¥¿ $OVERALL_INK_RETURN ¤È $OVERALL_LOGICAL_RETURN ¤¬@c NULL 
2203     ¤Ç¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï¥Æ¥­¥¹¥ÈÁ´ÂΤΥµ¥¤¥º¤â·×»»¤·¡¢·ë²Ì¤ò
2204     $OVERALL_INK_RETURN ¤È $OVERALL_LOGICAL_RETURN ¤Ç»Ø¤µ¤ì¤ë¹½Â¤¤Î¥á
2205     ¥ó¥Ð¤ËÊݸ¤¹¤ë¡£
2206
2207     $CONTROL->two_dimensional ¤¬0¤Ç¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤ÏºÇ½é¤Î¹Ô¤Îʸ»ú
2208     ¤Î¥µ¥¤¥º¤À¤±¤ò·×»»¤¹¤ë¡£ */
2209
2210 int
2211 mdraw_text_per_char_extents (MFrame *frame,
2212                              MText *mt, int from, int to,
2213                              MDrawControl *control,
2214                              MDrawMetric *ink_array_return,
2215                              MDrawMetric *logical_array_return,
2216                              int array_size,
2217                              int *num_chars_return,
2218                              MDrawMetric *overall_ink_return,
2219                              MDrawMetric *overall_logical_return)
2220 {
2221   MGlyphString *gstring;
2222   MGlyph *g;
2223   int x;
2224
2225   ASSURE_CONTROL (control);
2226   *num_chars_return = to - from;
2227   if (array_size < *num_chars_return)
2228     return 0;
2229   if (overall_logical_return)
2230     memset (overall_logical_return, 0, sizeof (MDrawMetric));
2231   if (overall_ink_return)
2232     memset (overall_ink_return, 0, sizeof (MDrawMetric));
2233
2234   M_CHECK_RANGE (mt, from, to, -1, 0);
2235   gstring = get_gstring (frame, mt, from, to, control);
2236   if (! gstring)
2237     {
2238       *num_chars_return = 0;
2239       return 0;
2240     }
2241
2242   for (g = MGLYPH (1), x = 0; g->type != GLYPH_ANCHOR;)
2243     if (g->pos >= from && g->pos < to)
2244       {
2245         int start = g->pos;
2246         int end = g->to;
2247         int width = g->width;
2248         int lbearing = g->lbearing;
2249         int rbearing = g->rbearing;
2250         int ascent = g->ascent;
2251         int descent = g->descent;
2252         int logical_ascent = g->rface->rfont->ascent;
2253         int logical_descent = g->rface->rfont->descent;
2254
2255         for (g++; g->type != GLYPH_ANCHOR && g->pos == start; g++)
2256           {
2257             if (lbearing < width + g->lbearing)
2258               lbearing = width + g->lbearing;
2259             if (rbearing < width + g->rbearing)
2260               rbearing = width + g->rbearing;
2261             width += g->width;
2262             if (ascent < g->ascent)
2263               ascent = g->ascent;
2264             if (descent < g->descent)
2265               descent = g->descent;
2266           }
2267
2268         if (end > to)
2269           end = to;
2270         while (start < end)
2271           {
2272             ink_array_return[start - from].x = x + lbearing;
2273             ink_array_return[start - from].y = - ascent;
2274             ink_array_return[start - from].width = rbearing - lbearing;
2275             ink_array_return[start - from].height = ascent + descent;
2276             logical_array_return[start - from].x = x;
2277             logical_array_return[start - from].y = - logical_descent;
2278             logical_array_return[start - from].height
2279               = logical_ascent + logical_descent;
2280             logical_array_return[start - from].width = width;
2281             start++;
2282           }
2283         x += width;
2284       }
2285
2286   if (overall_ink_return)
2287     {
2288       overall_ink_return->y = - gstring->line_ascent;
2289       overall_ink_return->x = gstring->lbearing;
2290       overall_ink_return->width = x - gstring->lbearing;
2291       overall_ink_return->height = gstring->height;
2292     }
2293   if (overall_logical_return)
2294     {
2295       overall_logical_return->y = - gstring->ascent;
2296       overall_logical_return->x = 0;
2297       overall_logical_return->width = x;
2298       overall_logical_return->height = gstring->ascent + gstring->descent;
2299     }
2300
2301   M17N_OBJECT_UNREF (gstring->top);
2302   return 1;
2303 }
2304
2305 /*=*/
2306
2307 /***en
2308     @brief Return the character position nearest to the coordinates.
2309
2310     The mdraw_coordinates_position () function checks which character
2311     is to be drawn at coordinate ($X, $Y) when the text between $FROM
2312     and $TO of M-text $MT is drawn at the coordinate (0, 0) using the
2313     mdraw_text_with_control () function with the drawing control
2314     object $CONTROL.  Here, the character position means the number of
2315     characters that precede the character in question in $MT, that is,
2316     the character position of the first character is 0.
2317
2318     $FRAME is used only to get the default face information.
2319
2320     @return
2321     If the glyph image of a character covers coordinate ($X, $Y),
2322     mdraw_coordinates_position () returns the character position of
2323     that character.\n\n
2324     If $Y is less than the minimum Y-coordinate of the drawn area, it
2325     returns $FROM.\n\n\n
2326     If $Y is greater than the maximum Y-coordinate of the drawn area,
2327     it returns $TO.\n\n\n
2328     If $Y fits in with the drawn area but $X is less than the minimum
2329     X-coordinate, it returns the character position of the first
2330     character drawn on the line $Y.\n\n\n
2331     If $Y fits in with the drawn area but $X is greater than the
2332     maximum X-coordinate, it returns the character position of the
2333     last character drawn on the line $Y.  */
2334
2335 /***ja
2336     @brief »ØÄꤷ¤¿ºÂɸ¤ËºÇ¤â¶á¤¤Ê¸»ú¤Îʸ»ú°ÌÃÖ¤òÆÀ¤ë.
2337
2338     ´Ø¿ô mdraw_coordinates_position () ¤Ï¡¢´Ø¿ô 
2339     mdraw_text_with_control () ¤¬ÉÁ²èÀ©¸æ¥ª¥Ö¥¸¥§¥¯¥È $CONTROL ¤òÍѤ¤
2340     ¤ÆM-text $MT ¤Î $FROM ¤«¤é $TO ¤Þ¤Ç¤òºÂɸ (0, 0) ¤òµ¯ÅÀ¤È¤·¤ÆÉÁ²è
2341     ¤·¤¿¾ì¹ç¤Ë¡¢ºÂɸ ($X, $Y) ¤ËÉÁ²è¤µ¤ì¤ëʸ»ú¤Îʸ»ú°ÌÃÖ¤òÊÖ¤¹¡£¤³¤³¤Ç
2342     Ê¸»ú°ÌÃ֤Ȥϡ¢Åö³º M-text Ãæ¤Ë¤ª¤¤¤Æ¤½¤Îʸ»ú¤¬ºÇ½é¤«¤é²¿ÈÖÌܤ«¤ò¼¨
2343     ¤¹À°¿ô¤Ç¤¢¤ë¡£¤¿¤À¤·ºÇ½é¤Îʸ»ú¤Îʸ»ú°ÌÃÖ¤Ï0¤È¤¹¤ë¡£
2344
2345     $FRAME ¤Ï¥Ç¥Õ¥©¥ë¥È¤Î¥Õ¥§¡¼¥¹¤Î¾ðÊó¤òÆÀ¤ë¤¿¤á¤À¤±¤ËÍѤ¤¤é¤ì¤ë¡£
2346
2347     @return
2348     ºÂɸ ($X, $Y) ¤¬¤¢¤ëʸ»ú¤Î¥°¥ê¥Õ¤Çʤ¤ï¤ì¤ë¾ì¹ç¡¢ ´Ø¿ô 
2349     mdraw_coordinates_position () ¤Ï¤½¤Îʸ»ú¤Îʸ»ú°ÌÃÖ¤òÊÖ¤¹¡£
2350
2351     ¤â¤· $Y ¤¬ÉÁ²èÎΰè¤ÎºÇ¾®YºÂɸ¤è¤ê¤â¾®¤µ¤¤¤Ê¤é¤Ð $FROM ¤òÊÖ¤¹¡£
2352
2353     ¤â¤· $Y ¤¬ÉÁ²èÎΰè¤ÎºÇÂçYºÂɸ¤è¤ê¤âÂ礭¤¤¤Ê¤é¤Ð $TO ¤òÊÖ¤¹¡£
2354
2355     ¤â¤· $Y ¤¬ÉÁ²èÎΰè¤Ë¾è¤Ã¤Æ¤¤¤Æ¤«¤Ä $X ¤¬ÉÁ²èÎΰè¤ÎºÇ¾®XºÂɸ¤è¤ê¤â
2356     ¾®¤µ¤¤¾ì¹ç¤Ï¡¢Ä¾Àþ y = $Y ¾å¤ËÉÁ²è¤µ¤ì¤ëºÇ½é¤Îʸ»ú¤Îʸ»ú°ÌÃÖ¤òÊÖ¤¹¡£
2357
2358     ¤â¤· $Y ¤¬ÉÁ²èÎΰè¤Ë¾è¤Ã¤Æ¤¤¤Æ¤«¤Ä $X ¤¬ÉÁ²èÎΰè¤ÎºÇÂçXºÂɸ¤è¤ê¤â
2359     Â礭¤¤¾ì¹ç¤Ï¡¢Ä¾Àþ y = $Y ¾å¤ËÉÁ²è¤µ¤ì¤ëºÇ¸å¤Îʸ»ú¤Îʸ»ú°ÌÃÖ¤òÊÖ¤¹¡£ */
2360
2361 int
2362 mdraw_coordinates_position (MFrame *frame, MText *mt, int from, int to,
2363                             int x_offset, int y_offset, MDrawControl *control)
2364 {
2365   MGlyphString *gstring;
2366   int y = 0;
2367   int width;
2368   MGlyph *g;
2369
2370   M_CHECK_POS_X (mt, from, -1);
2371   if (to > mtext_nchars (mt) + (control->cursor_width != 0))
2372     to = mtext_nchars (mt) + (control->cursor_width != 0);
2373   else if (to < from)
2374     to = from;
2375
2376   if (from == to)
2377     return from;
2378   ASSURE_CONTROL (control);
2379   gstring = get_gstring (frame, mt, from, to, control);
2380   while (y + gstring->line_descent <= y_offset
2381          && gstring->to < to)
2382     {
2383       from = gstring->to;
2384       y += gstring->line_descent;
2385       M17N_OBJECT_UNREF (gstring->top);
2386       gstring = get_gstring (frame, mt, from, to, control);
2387       y += gstring->line_ascent;
2388     }
2389
2390   /* Accumulate width of glyphs in WIDTH until it exceeds X. */
2391   if (! control->orientation_reversed)
2392     {
2393       width = gstring->indent;
2394       for (g = MGLYPH (1); g[1].type != GLYPH_ANCHOR; g++)
2395         if (g->pos >= from && g->pos < to)
2396           {
2397             width += g->width;
2398             if (width > x_offset)
2399               break;
2400           }
2401     }
2402   else
2403     {
2404       width = - gstring->indent;
2405       for (g = MGLYPH (gstring->used - 2); g->type != GLYPH_ANCHOR; g--)
2406         if (g->pos >= from && g->pos < to)
2407           {
2408             width -= g->width;
2409             if (width < x_offset)
2410               break;
2411           }
2412     }
2413   from = g->pos;
2414   M17N_OBJECT_UNREF (gstring->top);
2415
2416   return from;
2417 }
2418
2419 /*=*/
2420
2421 /***en
2422     @brief Compute information about a glyph.
2423
2424     The mdraw_glyph_info () function computes information about a
2425     glyph that covers a character at position $POS of the M-text $MT
2426     assuming that the text is drawn from the character at $FROM of $MT
2427     on a window of frame $FRAME using the mdraw_text_with_control ()
2428     function with the drawing control object $CONTROL.
2429
2430     The information is stored in the members of $INFO.  */
2431 /***ja
2432     @brief ¥°¥ê¥Õ¤Ë´Ø¤¹¤ë¾ðÊó¤ò·×»»¤¹¤ë.
2433
2434     ´Ø¿ô mdraw_glyph_info () ¤Ï¡¢´Ø¿ô mdraw_text_with_control () ¤¬ÉÁ
2435     ²èÀ©¸æ¥ª¥Ö¥¸¥§¥¯¥È $CONTROL ¤òÍѤ¤¤ÆM-text $MT ¤Î $FROM ¤«¤é $TO 
2436     ¤Þ¤Ç¤ò¥Õ¥ì¡¼¥à $FRAME ¤ËÉÁ²è¤·¤¿¾ì¹ç¡¢M-text ¤Îʸ»ú°ÌÃÖ $POS ¤Îʸ
2437     »ú¤òʤ¤¦¥°¥ê¥Õ¤Ë´Ø¤¹¤ë¾ðÊó¤ò·×»»¤¹¤ë¡£
2438
2439     ¾ðÊó¤Ï$INFO ¤Î¥á¥ó¥Ð¤ËÊÝ»ý¤µ¤ì¤ë¡£  */
2440
2441 /***
2442     @seealso
2443     MDrawGlyphInfo
2444 */
2445
2446 int
2447 mdraw_glyph_info (MFrame *frame, MText *mt, int from, int pos,
2448                   MDrawControl *control, MDrawGlyphInfo *info)
2449 {
2450   MGlyphString *gstring;
2451   MGlyph *g;
2452   int y = 0;
2453
2454   M_CHECK_RANGE_X (mt, from, pos, -1);
2455
2456   ASSURE_CONTROL (control);
2457   gstring = get_gstring (frame, mt, from, pos + 1, control);
2458   if (! gstring)
2459     MERROR (MERROR_DRAW, -1);
2460   while (gstring->to <= pos)
2461     {
2462       y += gstring->line_descent;
2463       M17N_OBJECT_UNREF (gstring->top);
2464       gstring = get_gstring (frame, mt, gstring->to, pos + 1, control);
2465       y += gstring->line_ascent;
2466     }
2467   info->line_from = gstring->from;
2468   if (info->line_from < from)
2469     info->line_from = from;
2470   info->line_to = gstring->to;
2471
2472   info->y = y;
2473   if (! control->orientation_reversed)
2474     {
2475       info->x = gstring->indent;
2476       for (g = MGLYPH (1); g->pos > pos || g->to <= pos; g++)
2477         info->x += g->width;
2478     }
2479   else
2480     {
2481       info->x = - gstring->indent;
2482       for (g = MGLYPH (gstring->used - 2); g->pos > pos || g->to <= pos; g--)
2483         info->x -= g->width;
2484       while (g[-1].to == g->to)
2485         g--;
2486     }
2487   info->from = g->pos;
2488   info->to = g->to;
2489   info->this.x = g->lbearing;
2490   info->this.y = - gstring->line_ascent;
2491   info->this.height = gstring->height;
2492   if (g->rface->rfont)
2493     info->font = &g->rface->rfont->font;
2494   else
2495     info->font = NULL;
2496   /* info->this.width is calculated later.  */
2497
2498   if (info->from > info->line_from)
2499     {
2500       /* The logically previous glyph is on this line.  */
2501       MGlyph *g_tmp = find_glyph_in_gstring (gstring, info->from - 1, 1);
2502
2503       info->prev_from = g_tmp->pos;
2504     }
2505   else if (info->line_from > 0)
2506     {
2507       /* The logically previous glyph is on the previous line.  */
2508       MGlyphString *gst = get_gstring (frame, mt, gstring->from - 1,
2509                                        gstring->from, control);
2510       MGlyph *g_tmp = find_glyph_in_gstring (gst, info->from - 1, 1);
2511
2512       info->prev_from = g_tmp->pos;
2513       M17N_OBJECT_UNREF (gst->top);
2514     }
2515   else
2516     info->prev_from = -1;
2517
2518   if (GLYPH_INDEX (g) > 1)
2519     info->left_from = g[-1].pos, info->left_to = g[-1].to;
2520   else if (! control->orientation_reversed)
2521     {
2522       if (info->line_from > 0)
2523         {
2524           MGlyph *g_tmp;
2525           MGlyphString *gst;
2526           int p = gstring->from - 1;
2527
2528           gst = get_gstring (frame, mt, p, gstring->from, control);
2529           g_tmp = gst->glyphs + (gst->used - 2);
2530           info->left_from = g_tmp->pos, info->left_to = g_tmp->to;
2531           M17N_OBJECT_UNREF (gst->top);
2532         }
2533       else
2534         info->left_from = info->left_to = -1;
2535     }
2536   else
2537     {
2538       if (gstring->to + (control->cursor_width == 0) <= mtext_nchars (mt))
2539         {
2540           MGlyph *g_tmp;
2541           MGlyphString *gst;
2542           int p = gstring->to;
2543
2544           gst = get_gstring (frame, mt, p, p + 1, control);
2545           g_tmp = gst->glyphs + (gst->used - 2);
2546           info->left_from = g_tmp->pos, info->left_to = g_tmp->to;
2547           M17N_OBJECT_UNREF (gst->top);
2548         }
2549       else
2550         info->left_from = info->left_to = -1;
2551     }
2552
2553   if (info->to < gstring->to)
2554     {
2555       /* The logically next glyph is on this line.   */
2556       MGlyph *g_tmp = find_glyph_in_gstring (gstring, info->to, 0);
2557
2558       info->next_to = g_tmp->to;
2559     }
2560   else if (info->to + (control->cursor_width == 0) <= mtext_nchars (mt))
2561     {
2562       /* The logically next glyph is on the next line.   */
2563       int p = info->to;
2564       MGlyphString *gst = get_gstring (frame, mt, p, p + 1, control);
2565       MGlyph *g_tmp = find_glyph_in_gstring (gst, p, 0);
2566
2567       info->next_to = g_tmp->to;
2568       M17N_OBJECT_UNREF (gst->top);
2569     }
2570   else
2571     info->next_to = -1;
2572
2573   for (info->this.width = (g++)->width;
2574        g->pos == pos && g->type != GLYPH_ANCHOR;
2575        info->this.width += (g++)->width);
2576
2577   if (g->type != GLYPH_ANCHOR)
2578     info->right_from = g->pos, info->right_to = g->to;
2579   else if (! control->orientation_reversed)
2580     {
2581       if (gstring->to + (control->cursor_width == 0) <= mtext_nchars (mt))
2582         {
2583           pos = gstring->to;
2584           M17N_OBJECT_UNREF (gstring->top);
2585           gstring = get_gstring (frame, mt, pos, pos + 1, control);
2586           g = MGLYPH (1);
2587           info->right_from = g->pos, info->right_to = g->to;
2588         }
2589       else
2590         info->right_from = info->right_to = -1;
2591     }
2592   else
2593     {
2594       if (info->line_from > 0)
2595         {
2596           pos = gstring->from - 1;
2597           M17N_OBJECT_UNREF (gstring->top);
2598           gstring = get_gstring (frame, mt, pos, pos + 1, control);
2599           g = MGLYPH (1);
2600           info->right_from = g->pos, info->right_to = g->to;
2601         }
2602       else
2603         info->right_from = info->right_to = -1;
2604     }
2605
2606   M17N_OBJECT_UNREF (gstring->top);
2607   return 0;
2608 }
2609
2610 /*=*/
2611
2612 /***en
2613     @brief Draw one or more textitems.
2614
2615     The mdraw_text_items () function draws one or more M-texts on
2616     window $WIN of $FRAME at coordinate ($X, $Y).  $ITEMS is an array
2617     of the textitems to be drawn and $NITEMS is the number of
2618     textimtems in the array.  */
2619
2620 /***ja
2621     @brief textitem ¤òɽ¼¨¤¹¤ë.
2622
2623     ´Ø¿ô mdraw_text_items () ¤Ï¡¢°ì¸Ä°Ê¾å¤Î¥Æ¥­¥¹¥È¥¢¥¤¥Æ¥à¤ò¡¢¥Õ¥ì¡¼
2624     ¥à $FRAME ¤Î¥¦¥£¥ó¥É¥¦ $WIN ¤ÎºÂɸ ($X, $Y) ¤Ëɽ¼¨¤¹¤ë¡£$ITEMS ¤Ï
2625     É½¼¨¤¹¤Ù¤­¥Æ¥­¥¹¥È¥¢¥¤¥Æ¥à¤ÎÇÛÎó¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ê¡¢$NITEMS ¤Ï¤½¤Î
2626     ¸Ä¿ô¤Ç¤¢¤ë¡£
2627
2628     @latexonly \IPAlabel{mdraw_text_items} @endlatexonly  */
2629
2630 /***
2631     @seealso
2632     MTextItem, mdraw_text ().  */
2633
2634 void
2635 mdraw_text_items (MFrame *frame, MDrawWindow win, int x, int y,
2636                   MDrawTextItem *items, int nitems)
2637 {
2638   while (nitems-- > 0)
2639     {
2640       if (items->face)
2641         mtext_push_prop (items->mt, 0, mtext_nchars (items->mt), Mface,
2642                          items->face);
2643       mdraw_text_with_control (frame, win, x, y,
2644                                items->mt, 0, mtext_nchars (items->mt),
2645                                items->control);
2646       x += mdraw_text_extents (frame, items->mt, 0, mtext_nchars (items->mt),
2647                                items->control, NULL, NULL, NULL);
2648       x += items->delta;
2649       if (items->face)
2650         mtext_pop_prop (items->mt, 0, mtext_nchars (items->mt), Mface);
2651     }
2652 }
2653
2654 /*=*/
2655 /***en 
2656       @brief   calculate a line breaking position.
2657
2658       The function mdraw_default_line_break () calculates a line
2659       breaking position based on the line number $LINE and the
2660       coordinate $Y, when a line is too long to fit within the width
2661       limit.  $POS is the position of the character next to the last
2662       one that fits within the limit.  $FROM is the position of the
2663       first character of the line, and TO is the position of the last
2664       character displayed on the line if there were not width limit.
2665       LINE and Y are reset to 0 when a line is broken by a newline
2666       character, and incremented each time when a long line is broken
2667       because of the width limit.  
2668
2669       @return 
2670       This function returns a character position to break the
2671       line.
2672
2673 */
2674 /***ja 
2675       @brief ²þ¹Ô°ÌÃÖ¤ò·×»»¤¹¤ë.
2676
2677       ´Ø¿ô mdraw_default_line_break () ¤Ï¡¢¹Ô¤¬ºÇÂçÉýÃæ¤Ë¼ý¤Þ¤é¤Ê¤¤¾ì
2678       ¹ç¤Ë¹Ô¤ò²þ¤á¤ë°ÌÃÖ¤ò¡¢¹ÔÈÖ¹æ LINE ¤ÈºÂɸ Y ¤Ë´ð¤Å¤¤¤Æ·×»»¤¹¤ë¡£
2679       $POS ¤ÏºÇÂçÉý¤Ë¼ý¤Þ¤ëºÇ¸å¤Îʸ»ú¤Î¼¡¤Îʸ»ú¤Î°ÌÃ֤Ǥ¢¤ë¡£$FROM ¤Ï
2680       ¹Ô¤ÎºÇ½é¤Îʸ»ú¤Î°ÌÃÖ¡¢$TO ¤ÏºÇÂçÉý¤¬»ØÄꤵ¤ì¤Æ¤¤¤Ê¤±¤ì¤Ð¤½¤Î¹Ô¤Ë
2681       É½¼¨¤µ¤ì¤ëºÇ¸å¤Îʸ»ú¤Î°ÌÃ֤Ǥ¢¤ë¡£ LINE ¤È Y ¤Ï²þ¹Ôʸ»ú¤Ë¤è¤Ã¤Æ
2682       ¹Ô¤¬²þ¤Þ¤Ã¤¿ºÝ¤Ë¤Ï 0 ¤Ë¥ê¥»¥Ã¥È¤µ¤ì¡¢ºÇÂçÉý¤Ë¤è¤Ã¤Æ¹Ô¤¬²þ¤Þ¤Ã¤¿
2683       ¾ì¹ç¤Ë¤Ï 1 ¤Å¤ÄÁý¤ä¤µ¤ì¤ë¡£
2684
2685       @return 
2686       ¤³¤Î´Ø¿ô¤Ï¹Ô¤ò²þ¤á¤ëʸ»ú°ÌÃÖ¤òÊÖ¤¹¡£
2687 */
2688
2689 int
2690 mdraw_default_line_break (MText *mt, int pos,
2691                           int from, int to, int line, int y)
2692 {
2693   int c = mtext_ref_char (mt, pos);
2694   int orig_pos = pos;
2695
2696   if (c == ' ' || c == '\t')
2697     {
2698       pos++;
2699       while (pos < to
2700              && ((c = mtext_ref_char (mt, pos)) == ' ' || c == '\t'))
2701         pos++;
2702     }
2703   else
2704     {
2705       while (pos > from)
2706         {
2707           if (c == ' ' || c == '\t')
2708             break;
2709           pos--;
2710           c = mtext_ref_char (mt, pos);
2711         }
2712       if (pos == from)
2713         pos = orig_pos;
2714       else
2715         pos++;
2716     }
2717   return pos;
2718 }
2719
2720 /*=*/
2721
2722 /***en
2723     @brief Obtain per character dimension information.
2724
2725     The mdraw_per_char_extents () function computes the text dimension
2726     of each character in M-text $MT.  The faces given as text
2727     properties in $MT and the default face of frame $FRAME determine
2728     the fonts to draw the text.  Each successive element in
2729     $ARRAY_RETURN is set to the drawn metrics of successive
2730     characters, which is relative to the origin of the drawing, and a
2731     rectangle for each character in $MT.  The number of elements of
2732     $ARRAY_RETURN must be equal to or greater than the number of
2733     characters in $MT.
2734
2735     If pointer $OVERALL_RETURN is not @c NULL, this function also
2736     computes the extents of the overall text and stores the results in
2737     the members of the structure pointed to by $OVERALL_RETURN  */
2738
2739 /***ja
2740     @brief M-text ¤Îʸ»úËè¤Îɽ¼¨ÈϰϾðÊó¤òÆÀ¤ë.
2741
2742     ´Ø¿ô mdraw_per_char_extents () ¤Ï¡¢M-text $MT Ãæ¤Î³Æʸ»ú¤Îɽ¼¨ÈÏ°Ï
2743     ¤ò·×»»¤¹¤ë¡£¤³¤Î·×»»¤ËÍѤ¤¤ë¥Õ¥©¥ó¥È¤Ï¡¢$MT ¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ç
2744     »ØÄꤵ¤ì¤¿¥Õ¥§¡¼¥¹¤È¡¢¥Õ¥ì¡¼¥à $FRAME ¤Î¥Ç¥Õ¥©¥ë¥È¥Õ¥§¡¼¥¹¤Ë¤è¤Ã¤Æ·è
2745     ¤Þ¤ë¡£$ARRAY_RETURN ¤Î³ÆÍ×ÁǤϡ¢Åö³º M-text Ãæ¤Î³Æʸ»ú¤Îɽ¼¨ÈÏ°Ï
2746     ¾ðÊó¤Ë¤è¤Ã¤Æ½ç¤ËËä¤á¤é¤ì¤ë¡£¤³¤Îɽ¼¨ÈϰϾðÊó¤Ï¡¢M-text ¤Îɽ¼¨¸¶ÅÀ
2747     ¤«¤é¤ÎÁêÂаÌÃ֤Ǥ¢¤ë¡£$ARRAY_RETURN ¤ÎÍ×ÁÇ¿ô¤Ï¡¢M-text ¤Îʸ»ú¿ô°Ê
2748     ¾å¤Ç¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£
2749
2750     ¥Ý¥¤¥ó¥¿ $OVERALL_RETURN ¤¬ @c NULL ¤Ç¤Ê¤¤¾ì¹ç¤Ï¡¢¥Æ¥­¥¹¥ÈÁ´ÂΤÎɽ
2751     ¼¨ÈϰϾðÊó¤â·×»»¤·¡¢¤½¤Î·ë²Ì¤ò $OVERALL_RETURN ¤Î»Ø¤¹¹½Â¤ÂΤ˳ÊǼ
2752     ¤¹¤ë¡£
2753
2754     @latexonly \IPAlabel{mdraw_per_char_extents} @endlatexonly  */
2755
2756 void
2757 mdraw_per_char_extents (MFrame *frame, MText *mt,
2758   MDrawMetric *array_return,
2759   MDrawMetric *overall_return)
2760 {
2761 }
2762
2763 /***en 
2764     @brief clear cached information.    
2765
2766     The mdraw_clear_cache () function clear cached information
2767     on M-text $MT that was attached by any of the drawing functions.
2768     When the behaviour of `format' or `line_break'
2769     member functions of MDrawControl is changed, the cache must be cleared.
2770
2771     @seealso
2772     MDrawControl */
2773 /***ja 
2774     @brief ¥­¥ã¥Ã¥·¥å¾ðÊó¤ò¾Ã¤¹.
2775
2776     ´Ø¿ô mdraw_clear_cache () ¤ÏÉÁ²è´Ø¿ô¤Ë¤è¤Ã¤Æ M-text $MT ¤ËÉÕ²Ã
2777     ¤µ¤ì¤¿¥­¥ã¥Ã¥·¥å¾ðÊó¤ò¤¹¤Ù¤Æ¾Ãµî¤¹¤ë¡£MDrawControl ¤Î `format' ¤¢
2778     ¤ë¤¤¤Ï `line_break' ¥á¥ó¥Ð´Ø¿ô¤Î¿¶Éñ¤¤¤¬ÊѤï¤Ã¤¿¾ì¹ç¤Ë¤Ï¥­¥ã¥Ã¥·¥å
2779     ¤ò¾Ãµî¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
2780     @seealso
2781     MDrawControl */
2782
2783 void
2784 mdraw_clear_cache (MText *mt)
2785 {
2786   mtext_pop_prop (mt, 0, mtext_nchars (mt), M_glyph_string);
2787 }
2788
2789 /*** @} */
2790
2791 /*
2792   Local Variables:
2793   coding: euc-japan
2794   End:
2795 */