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