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