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