(compose_glyph_string): Fix for the case of category
[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 (category != Mnil && 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_SPACE;
1460           gstring->glyphs[1].c = '\n';
1461           gstring->glyphs[1].code = '\n';
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++;
1471       g->rface = frame->rface;
1472       g->pos = g->to = pos;
1473       gstring->to = pos;
1474     }
1475   else
1476     {
1477       M17N_OBJECT (gstring, free_gstring, MERROR_DRAW);
1478       MLIST_INIT1 (gstring, glyphs, 128);
1479       gstring_num++;
1480     }
1481
1482   gstring->frame = frame;
1483   gstring->tick = frame->tick;
1484   gstring->top = gstring;
1485   gstring->control = *control;
1486   gstring->indent = gstring->width_limit = 0;
1487   if (control->format)
1488     (*control->format) (line, y, &(gstring->indent), &(gstring->width_limit));
1489   else
1490     gstring->width_limit = control->max_line_width;
1491   gstring->anti_alias = control->anti_alias;
1492   return gstring;
1493 }
1494
1495 /* Truncate the line width of GSTRING to GSTRING->width_limit.  */
1496
1497 static void
1498 truncate_gstring (MFrame *frame, MText *mt, MGlyphString *gstring)
1499 {
1500   int width;
1501   int i;
1502   int *pos_width;
1503   MGlyph *g;
1504   int pos;
1505
1506   /* Setup the array POS_WIDTH so that POS_WIDTH[I - GSTRING->from] is
1507      a width of glyphs for the character at I of MT.  If I is not a
1508      beginning of a grapheme cluster, the corresponding element is
1509      0.  */
1510   MTABLE_ALLOCA (pos_width, gstring->to - gstring->from, MERROR_DRAW);
1511   memset (pos_width, 0, sizeof (int) * (gstring->to - gstring->from));
1512   for (g = MGLYPH (1); g->type != GLYPH_ANCHOR; g++)
1513     pos_width[g->pos - gstring->from] += g->width;
1514   for (i = 0, width = 0; i < gstring->to - gstring->from; i++)
1515     {
1516       if (pos_width[i] > 0)
1517         {
1518           if (width + pos_width[i] > gstring->width_limit)
1519             break;
1520         }
1521       width += pos_width[i];
1522     }
1523
1524   pos = gstring->from + i;
1525   if (gstring->control.line_break)
1526     {
1527       pos = (*gstring->control.line_break) (mt, gstring->from + i,
1528                                             gstring->from, gstring->to, 0, 0);
1529       if (pos <= gstring->from)
1530         pos = gstring->from + 1;
1531       else if (pos >= gstring->to)
1532         pos = gstring->to;
1533     }
1534   else if (i == 0)
1535     pos++;
1536   compose_glyph_string (frame, mt, gstring->from, pos, gstring);
1537   layout_glyph_string (frame, gstring);
1538 }
1539
1540
1541 /* Return a gstring that covers a character at POS.  */
1542
1543 static MGlyphString *
1544 get_gstring (MFrame *frame, MText *mt, int pos, int to, MDrawControl *control)
1545 {
1546   MGlyphString *gstring = NULL;
1547
1548   if (pos < mtext_nchars (mt))
1549     {
1550       MTextProperty *prop = mtext_get_property (mt, pos, M_glyph_string);
1551
1552       if (prop
1553           && ((prop->start != 0
1554                && mtext_ref_char (mt, prop->start - 1) != '\n')
1555               || (prop->end < mtext_nchars (mt)
1556                   && mtext_ref_char (mt, prop->end - 1) != '\n')))
1557         {
1558           mtext_detach_property (prop);
1559           prop = NULL;
1560         }
1561       if (prop)
1562         {
1563           gstring = prop->val;
1564           if (gstring->frame != frame
1565               || gstring->tick != frame->tick
1566               || memcmp (control, &gstring->control,
1567                          (char *) (&control->with_cursor)
1568                          - (char *) (control))
1569               || control->cursor_width != gstring->control.cursor_width
1570               || control->cursor_bidi != gstring->control.cursor_bidi)
1571             {
1572               mtext_detach_property (prop);
1573               gstring = NULL;
1574             }
1575         }
1576     }
1577   else if (! control->cursor_width)
1578     return NULL;
1579
1580   if (gstring)
1581     {
1582       MGlyphString *gst;
1583       int offset;
1584
1585       offset = mtext_character (mt, pos, 0, '\n');
1586       if (offset < 0)
1587         offset = 0;
1588       else
1589         offset++;
1590       offset -= gstring->from;
1591       if (offset)
1592         for (gst = gstring; gst; gst = gst->next)
1593           {
1594             int i;
1595
1596             gst->from += offset;
1597             gst->to += offset;
1598             for (i = 0; i < gst->used; i++)
1599               {
1600                 gst->glyphs[i].pos += offset;
1601                 gst->glyphs[i].to += offset;
1602               }
1603           }
1604       M17N_OBJECT_REF (gstring);
1605     }
1606   else
1607     {
1608       int beg, end;
1609       int line = 0, y = 0;
1610
1611       if (pos < mtext_nchars (mt))
1612         {
1613           beg = mtext_character (mt, pos, 0, '\n');
1614           if (beg < 0)
1615             beg = 0;
1616           else
1617             beg++;
1618         }
1619       else
1620         beg = pos;
1621       end = mtext_nchars (mt) + (control->cursor_width != 0);
1622       gstring = alloc_gstring (frame, mt, beg, control, line, y);
1623       if (beg < mtext_nchars (mt))
1624         compose_glyph_string (frame, mt, beg, end, gstring);
1625       layout_glyph_string (frame, gstring);
1626       end = gstring->to;
1627       if (gstring->width_limit
1628           && gstring->width > gstring->width_limit)
1629         {
1630           MGlyphString *gst = gstring;
1631
1632           truncate_gstring (frame, mt, gst);
1633           while (gst->to < end)
1634             {
1635               line++, y += gst->height;
1636               gst->next = alloc_gstring (frame, mt, gst->from, control,
1637                                          line, y);
1638               gst->next->top = gstring;
1639               compose_glyph_string (frame, mt, gst->to, end, gst->next);
1640               gst = gst->next;
1641               layout_glyph_string (frame, gst);
1642               if (gst->width <= gst->width_limit)
1643                 break;
1644               truncate_gstring (frame, mt, gst);
1645             }
1646         }
1647
1648       if (! control->disable_caching && pos < mtext_nchars (mt))
1649         {
1650           MTextProperty *prop = mtext_property (M_glyph_string, gstring,
1651                                                 MTEXTPROP_VOLATILE_STRONG);
1652
1653           if (end > mtext_nchars (mt))
1654             end = mtext_nchars (mt);
1655           mtext_attach_property (mt, beg, end, prop);
1656           M17N_OBJECT_UNREF (prop);
1657         }
1658     }
1659
1660   while (gstring->to <= pos)
1661     {
1662       if (! gstring->next)
1663         mdebug_hook ();
1664       gstring = gstring->next;
1665     }
1666   gstring->control = *control;
1667
1668   return gstring;
1669 }
1670
1671
1672 static MDrawControl control_noop;
1673
1674 #define ASSURE_CONTROL(control) \
1675   if (! control)                \
1676     control = &control_noop;    \
1677   else
1678
1679
1680 static int
1681 draw_text (MFrame *frame, MDrawWindow win, int x, int y,
1682            MText *mt, int from, int to,
1683            MDrawControl *control)
1684 {
1685   MGlyphString *gstring;
1686
1687   M_CHECK_POS_X (mt, from, -1);
1688   ASSURE_CONTROL (control);
1689   if (to > mtext_nchars (mt) + (control->cursor_width != 0))
1690     to = mtext_nchars (mt) + (control->cursor_width != 0);
1691   else if (to < from)
1692     to = from;
1693
1694   gstring = get_gstring (frame, mt, from, to, control);
1695   if (! gstring)
1696     MERROR (MERROR_DRAW, -1);
1697   render_glyph_string (frame, win, x, y, gstring, from, to);
1698   from = gstring->to;
1699   while (from < to)
1700     {
1701       y += gstring->line_descent;
1702       M17N_OBJECT_UNREF (gstring->top);
1703       gstring = get_gstring (frame, mt, from, to, control);
1704       y += gstring->line_ascent;
1705       render_glyph_string (frame, win, x, y, gstring, from, to);
1706       from = gstring->to;
1707     }
1708   M17N_OBJECT_UNREF (gstring->top);
1709
1710   return 0;
1711 }
1712
1713
1714 static MGlyph *
1715 find_glyph_in_gstring (MGlyphString *gstring, int pos, int forwardp)
1716 {
1717   MGlyph *g;
1718
1719   if (forwardp)
1720     {
1721       for (g = MGLYPH (1); g->type != GLYPH_ANCHOR; g++)
1722         if (g->pos <= pos && g->to > pos)
1723           break;
1724     }
1725   else
1726     {
1727       for (g = MGLYPH (gstring->used - 2); g->type != GLYPH_ANCHOR; g--)
1728         if (g->pos <= pos && g->to > pos)
1729           break;
1730     }
1731   return g;
1732 }
1733
1734 \f
1735 /* for debugging... */
1736 char work[16];
1737
1738 char *
1739 dump_combining_code (int code)
1740 {
1741   char *vallign = "tcbB";
1742   char *hallign = "lcr";
1743   char *p;
1744   int off_x, off_y;
1745
1746   if (! code)
1747     return "none";
1748   if (COMBINING_BY_CLASS_P (code))
1749     code = combining_code_from_class (COMBINING_CODE_CLASS (code));
1750   work[0] = vallign[COMBINING_CODE_BASE_Y (code)];
1751   work[1] = hallign[COMBINING_CODE_BASE_X (code)];
1752   off_y = COMBINING_CODE_OFF_Y (code) - 128;
1753   off_x = COMBINING_CODE_OFF_X (code) - 128;
1754   if (off_y > 0)
1755     sprintf (work + 2, "+%d", off_y);
1756   else if (off_y < 0)
1757     sprintf (work + 2, "%d", off_y);
1758   else if (off_x == 0)
1759     sprintf (work + 2, ".");
1760   p = work + strlen (work);
1761   if (off_x > 0)
1762     sprintf (p, ">%d", off_x);
1763   else if (off_x < 0)
1764     sprintf (p, "<%d", -off_x);
1765   p += strlen (p);
1766   p[0] = vallign[COMBINING_CODE_ADD_Y (code)];
1767   p[1] = hallign[COMBINING_CODE_ADD_X (code)];
1768   p[2] = '\0';
1769   return work;
1770 }
1771
1772 void
1773 dump_gstring (MGlyphString *gstring, int indent)
1774 {
1775   char *prefix = (char *) alloca (indent + 1);
1776   MGlyph *g, *last_g = gstring->glyphs + gstring->used;
1777
1778   memset (prefix, 32, indent);
1779   prefix[indent] = 0;
1780
1781   fprintf (stderr, "(glyph-string");
1782
1783   for (g = MGLYPH (0); g < last_g; g++)
1784     fprintf (stderr,
1785              "\n%s  (%02d %s pos:%d-%d c:%04X code:%04X face:%x cmb:%s w:%02d bidi:%d)",
1786              prefix,
1787              g - gstring->glyphs,
1788              (g->type == GLYPH_SPACE ? "SPC": g->type == GLYPH_PAD ? "PAD"
1789               : g->type == GLYPH_ANCHOR ? "ANC"
1790               : g->type == GLYPH_BOX ? "BOX" : "CHR"),
1791              g->pos, g->to, g->c, g->code, (unsigned) g->rface,
1792              dump_combining_code (g->combining_code),
1793              g->width, g->bidi_level);
1794   fprintf (stderr, ")");
1795 }
1796 \f
1797
1798 /* m17n-X internal APIs */
1799
1800 int
1801 mdraw__init ()
1802 {
1803   M_glyph_string = msymbol_as_managing_key ("  glyph-string");
1804
1805   memset (&scratch_gstring, 0, sizeof (scratch_gstring));
1806   MLIST_INIT1 (&scratch_gstring, glyphs, 3);
1807
1808   Minherited = msymbol ("inherited");
1809
1810   McatCc = msymbol ("Cc");
1811   McatCf = msymbol ("Cf");
1812
1813   MbidiR = msymbol ("R");
1814   MbidiAL = msymbol ("AL");
1815   MbidiRLE = msymbol ("RLE");
1816   MbidiRLO = msymbol ("RLO");
1817   MbidiBN = msymbol ("BN");
1818   MbidiS = msymbol ("S");
1819 #ifdef HAVE_FRIBIDI
1820   fribidi_set_mirroring (TRUE);
1821 #endif
1822
1823   return 0;
1824 }
1825
1826 void
1827 mdraw__fini ()
1828 {
1829   MLIST_FREE1 (&scratch_gstring, glyphs);
1830 }
1831
1832 /*** @} */
1833 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
1834
1835 \f
1836 /* External API */
1837 /*** @addtogroup m17nDraw */
1838 /*** @{ */
1839
1840 /*=*/
1841 /***en
1842     @brief Draw an M-text on a window.
1843
1844     The mdraw_text () function draws the text between $FROM and $TO of
1845     M-text $MT on window $WIN of frame $FRAME at coordinate ($X, $Y).
1846
1847     The appearance of the text (size, style, color, etc) is specified
1848     by the value of the text property whose key is @c Mface.  If the
1849     M-text or a part of the M-text does not have such a text property,
1850     the default face of $FRAME is used.
1851
1852     The font used to draw a character in the M-text is selected from
1853     the value of the fontset property of a face by the following
1854     algorithm:
1855
1856     <ol>
1857
1858     <li> Search the text properties given to the character for the one
1859          whose key is @c Mcharset; its value should be either a symbol
1860          specifying a charset or #Mnil.  If the value is #Mnil,
1861          proceed to the next step.
1862
1863          Otherwise, search the mapping table of the fontset for the
1864          charset.  If no entry is found proceed to the next step.  
1865
1866          If an entry is found, use one of the fonts in the entry that
1867          has a glyph for the character and that matches best with the
1868          face properties.  If no such font exists, proceed to the next
1869          step.
1870
1871     <li> Get the character property "script" of the character.  If it is
1872          inherited, get the script property from the previous
1873          characters.  If there is no previous character, or none of
1874          them has the script property other than inherited, proceed to
1875          the next step.
1876
1877          Search the text properties given to the character for the one
1878          whose key is @c Mlanguage; its value should be either a
1879          symbol specifying a language or @c Mnil.
1880
1881          Search the mapping table of the fontset for the combination
1882          of the script and language.  If no entry is found, proceed to
1883          the next step.  
1884
1885         If an entry is found, use one of the fonts in the entry that
1886          has a glyph for the character and that matches best with the
1887          face properties.  If no such font exists, proceed to the next
1888          step.
1889
1890     <li> Search the fall-back table of the fontset for a font that has
1891          a glyph of the character.  If such a font is found, use that
1892          font.
1893
1894     </ol>
1895
1896     If no font is found by the algorithm above, this function draws an
1897     empty box for the character.
1898
1899     This function draws only the glyph foreground.  To specify the
1900     background color, use mdraw_image_text () or
1901     mdraw_text_with_control ().
1902
1903     This function is the counterpart of <tt>XDrawString ()</tt>,
1904     <tt>XmbDrawString ()</tt>, and <tt>XwcDrawString ()</tt> functions
1905     in the X Window System.
1906
1907     @return
1908     If the operation was successful, mdraw_text () returns 0.  If an
1909     error is detected, it returns -1 and assigns an error code to the
1910     external variable #merror_code.  */
1911 /***ja
1912     @brief ¥¦¥£¥ó¥É¥¦¤Ë M-text ¤òÉÁ²è¤¹¤ë.
1913
1914     ´Ø¿ô mdraw_text () ¤Ï¡¢¥Õ¥ì¡¼¥à $FRAME ¤Î¥¦¥£¥ó¥É¥¦ $WIN ¤ÎºÂɸ 
1915     ($X, $Y) ¤Ë¡¢M-text $MT ¤Î $FROM ¤«¤é $TO ¤Þ¤Ç¤Î¥Æ¥­¥¹¥È¤ò
1916     ÉÁ²è¤¹¤ë¡£
1917
1918     ¥Æ¥­¥¹¥È¤Î¸«±É¤¨¡Ê¥Õ¥©¥ó¥È¡¢¥¹¥¿¥¤¥ë¡¢¿§¤Ê¤É¡Ë¤Ï¡¢¥­¡¼¤¬ @c Mface 
1919     ¤Ç¤¢¤ë¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤ÎÃͤˤè¤Ã¤Æ·è¤Þ¤ë¡£M-text ¤Î°ìÉô¤¢¤ë¤¤¤Ï
1920     Á´Éô¤Ë¤½¤Î¤è¤¦¤Ê¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤¬ÉÕ¤¤¤Æ¤¤¤Ê¤¤¾ì¹ç¤Ë¤Ï¡¢$FRAME 
1921     ¤Î¥Ç¥Õ¥©¥ë¥È¥Õ¥§¡¼¥¹¤¬ÍѤ¤¤é¤ì¤ë¡£
1922
1923     M-text ¤Î³Æʸ»ú¤òɽ¼¨¤¹¤ë¥Õ¥©¥ó¥È¤Ï¡¢¥Õ¥§¡¼¥¹¤Î fontset ¥×¥í¥Ñ¥Æ¥£
1924     ¤ÎÃͤ«¤é°Ê²¼¤Î¥¢¥ë¥´¥ê¥º¥à¤ÇÁª¤Ð¤ì¤ë¡£
1925
1926     <ol>
1927
1928     <li> ¤½¤Îʸ»ú¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Î¤¦¤Á¡¢¥­¡¼¤¬ @c Mcharset ¤Ç¤¢¤ë
1929          ¤â¤Î¤ÎÃͤòÄ´¤Ù¤ë¡£¤³¤ÎÃͤÏʸ»ú¥»¥Ã¥È¤òɽ¤ï¤¹¥·¥ó¥Ü¥ë¤« #Mnil 
1930          ¤Î¤É¤Á¤é¤«¤Ç¤¢¤ë¡£#Mnil ¤Ê¤é¤Ð¡¢¼¡¤Î¥¹¥Æ¥Ã¥×¤Ë¿Ê¤à¡£¤½¤¦¤Ç¤Ê
1931          ¤±¤ì¤Ð¡¢¤½¤Î¥Õ¥©¥ó¥È¥»¥Ã¥È¤Î¥Þ¥Ã¥Ô¥ó¥°¥Æ¡¼¥Ö¥ë¤«¤é¤½¤Îʸ»ú¥»¥Ã
1932          ¥ÈÍѤΤâ¤Î¤òõ¤¹¡£¥Õ¥©¥ó¥È¤¬¤ß¤Ä¤«¤é¤Ê¤±¤ì¤Ð¡¢¼¡¤Î¥¹¥Æ¥Ã¥×¤Ë
1933          ¿Ê¤à¡£
1934          
1935          ¤½¤Îʸ»ú¥»¥Ã¥ÈÍѤΥե©¥ó¥È¤¬¤ß¤Ä¤«¤ì¤Ð¡¢¤½¤ì¤é¤Î¤¦¤Á¸½ºß¤Îʸ
1936          »úÍѤΥ°¥ê¥Õ¤ò»ý¤Á¡¢¥Õ¥§¡¼¥¹¤Î³Æ¥×¥í¥Ñ¥Æ¥£¤ËºÇ¤â¤è¤¯¹çÃפ·¤Æ
1937          ¤¤¤ë¤â¤Î¤ò»È¤¦¡£¤½¤Î¤è¤¦¤Ê¥Õ¥©¥ó¥È¤¬Ìµ¤±¤ì¤Ð¼¡¤Î¥¹¥Æ¥Ã¥×¤Ë¿Ê
1938          ¤à¡£
1939
1940     <li> ¤½¤Îʸ»ú¤Îʸ»ú¥×¥í¥Ñ¥Æ¥£ "script" ¡Ê¥¹¥¯¥ê¥×¥È¡Ë¤òÄ´¤Ù¤ë¡£·Ñ
1941          ¾µ¤µ¤ì¤Æ¤¤¤ë¤Ê¤é¤Ð¤½¤ì°ÊÁ°¤Îʸ»ú¤Îʸ»ú¥×¥í¥Ñ¥Æ¥£ "script" ¤ò
1942          Ä´¤Ù¤ë¡£Á°¤Îʸ»ú¤¬¤Ê¤«¤Ã¤¿¤ê¡¢¤½¤Îʸ»ú¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Ã¤Æ¤¤¤Ê
1943          ¤«¤Ã¤¿¾ì¹ç¤Ë¤Ï¡¢¼¡¤Î¥¹¥Æ¥Ã¥×¤Ë¿Ê¤à¡£
1944
1945          ¤½¤Îʸ»ú¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Î¤¦¤Á¡¢¥­¡¼¤¬ @c Mlanguage ¤Ç¤¢
1946          ¤ë¤â¤Î¤ÎÃͤòÄ´¤Ù¤ë¡£¤³¤ÎÃͤϸÀ¸ì¤òɽ¤ï¤¹¥·¥ó¥Ü¥ë¤« @c Mnil ¤Î
1947          ¤¤¤º¤ì¤«¤Ç¤¢¤ë¡£
1948
1949          ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢¤½¤Î¸À¸ì¤È¥¹¥¯¥ê¥×¥È¤ÎÁȤ߹ç¤ï¤»ÍѤΥե©¥ó¥È
1950          ¥»¥Ã¥È¤ò¥Þ¥Ã¥Ô¥ó¥°¥Æ¡¼¥Ö¥ë¤«¤éõ¤¹¡£¸«¤Ä¤«¤é¤Ê¤±¤ì¤Ð¼¡¤Î¥¹¥Æ¥Ã
1951          ¥×¤Ë¿Ê¤à¡£
1952
1953          ¤½¤Î¤è¤¦¤Êʸ»ú¥»¥Ã¥ÈÍѤΥե©¥ó¥È¤¬¤ß¤Ä¤«¤ì¤Ð¡¢¤½¤ì¤é¤Î¤¦¤Á¸½
1954          ºß¤Îʸ»úÍѤΥ°¥ê¥Õ¤ò»ý¤Á¡¢¥Õ¥§¡¼¥¹¤Î³Æ¥×¥í¥Ñ¥Æ¥£¤ËºÇ¤â¤è¤¯¹ç
1955          Ãפ·¤Æ¤¤¤ë¤â¤Î¤ò»È¤¦¡£¤½¤Î¤è¤¦¤Ê¥Õ¥©¥ó¥È¤¬Ìµ¤±¤ì¤Ð¼¡¤Î¥¹¥Æ¥Ã
1956          ¥×¤Ë¿Ê¤à¡£
1957
1958     <li> ¤½¤Îʸ»ú¤Î¥°¥ê¥Õ¤ò»ý¤Ä¥Õ¥©¥ó¥È¤ò¡¢¥Õ¥©¥ó¥È¥»¥Ã¥È¤Îfall-back¥Æ¡¼
1959          ¥Ö¥ë¤«¤éõ¤¹¡£¥Õ¥©¥ó¥È¤¬¸«¤Ä¤«¤ì¤Ð¤½¤ì¤ò»È¤¦¡£
1960
1961     </ol>
1962
1963     °Ê¾å¤Î¥¢¥ë¥´¥ê¥º¥à¤Ç¥Õ¥©¥ó¥È¤¬¸«¤Ä¤«¤é¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï¤½¤Îʸ»ú
1964     ¤È¤·¤Æ¶õ¤Î»Í³Ñ·Á¤òɽ¼¨¤¹¤ë¡£
1965
1966     ¤³¤Î´Ø¿ô¤¬ÉÁ²è¤¹¤ë¤Î¤Ï¥°¥ê¥Õ¤ÎÁ°·Ê¤À¤±¤Ç¤¢¤ë¡£ÇØ·Ê¿§¤ò»ØÄꤹ¤ë¤Ë¤Ï¡¢
1967     ´Ø¿ô mdraw_image_text () ¤«´Ø¿ô mdraw_text_with_control () ¤ò»È¤¦
1968     ¤³¤È¡£
1969
1970     ¤³¤Î´Ø¿ô¤Ï¡¢X ¥¦¥£¥ó¥É¥¦¤Ë¤ª¤±¤ë´Ø¿ô <tt>XDrawString ()</tt>,
1971     <tt>XmbDrawString ()</tt>, <tt>XwcDrawString ()</tt> ¤ËÁêÅö¤¹¤ë¡£
1972
1973     @return
1974     ½èÍý¤¬À®¸ù¤·¤¿¾ì¹ç¡¢mdraw_text () ¤Ï 0 ÊÖ¤¹¡£¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì¤¿¾ì
1975     ¹ç¤Ï -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
1976
1977     @latexonly \IPAlabel{mdraw_text} @endlatexonly  */
1978
1979 /***
1980     @errors
1981     @c MERROR_RANGE
1982
1983     @seealso
1984     mdraw_image_text ()  */
1985
1986 int
1987 mdraw_text (MFrame *frame, MDrawWindow win, int x, int y,
1988             MText *mt, int from, int to)
1989 {
1990   MDrawControl control;
1991
1992   M_CHECK_WRITABLE (frame, MERROR_DRAW, -1);
1993   memset (&control, 0, sizeof control);
1994   control.as_image = 0;
1995   return draw_text (frame, win, x, y, mt, from, to, &control);
1996 }
1997
1998 /*=*/
1999
2000
2001 /***en
2002     @brief Draw an M-text on a window as an image.
2003
2004     The mdraw_image_text () function draws the text between $FROM and
2005     $TO of M-text $MT as image on window $WIN of frame $FRAME at
2006     coordinate ($X, $Y).
2007
2008     The way to draw a text is the same as in mdraw_text () except that
2009     this function also draws the background with the color specified
2010     by faces.
2011
2012     This function is the counterpart of <tt>XDrawImageString ()</tt>,
2013     <tt>XmbDrawImageString ()</tt>, and <tt>XwcDrawImageString ()</tt>
2014     functions in the X Window System.
2015
2016     @return
2017     If the operation was successful, mdraw_image_text () returns 0.
2018     If an error is detected, it returns -1 and assigns an error code
2019     to the external variable #merror_code.  */
2020
2021 /***ja
2022     @brief ¥Ç¥£¥¹¥×¥ì¥¤¤ËM-text ¤ò²èÁü¤È¤·¤ÆÉÁ¤¯.
2023   
2024     ´Ø¿ô mdraw_image_text () ¤Ï¡¢¥Õ¥ì¡¼¥à $FRAME ¤Î¥¦¥£¥ó¥É¥¦ $WIN ¤Î
2025     ºÂɸ ($X, $Y) ¤Ë¡¢M-text $MT ¤Î $FROM ¤«¤é $TO ¤Þ¤Ç¤Î¥Æ¥­¥¹¥È¤ò²è
2026     Áü¤È¤·¤ÆÉÁ¤¯¡£
2027
2028     ¥Æ¥­¥¹¥È¤ÎÉÁ²èÊýË¡¤Ï mdraw_text () ¤È¤Û¤ÜƱ¤¸¤Ç¤¢¤ë¤¬¡¢¤³¤Î´Ø¿ô¤Ç
2029     ¤Ï¥Õ¥§¡¼¥¹¤Ç»ØÄꤵ¤ì¤¿¿§¤ÇÇطʤâÉÁ¤¯ÅÀ¤¬°Û¤Ê¤Ã¤Æ¤¤¤ë¡£
2030
2031     ¤³¤Î´Ø¿ô¤Ï¡¢X ¥¦¥£¥ó¥É¥¦¤Ë¤ª¤±¤ë <tt>XDrawImageString ()</tt>,
2032     <tt>XmbDrawImageString ()</tt>, <tt>XwcDrawImageString ()</tt> ¤Ë
2033     ÁêÅö¤¹¤ë¡£
2034
2035     @return
2036     ½èÍý¤¬À®¸ù¤·¤¿¾ì¹ç¡¢mdraw_image_text () ¤Ï 0 ¤òÊÖ¤¹¡£¥¨¥é¡¼¤¬¸¡½Ð
2037     ¤µ¤ì¤¿¾ì¹ç¤Ï -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #m_errro ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ
2038     ¤ë¡£
2039
2040     @latexonly \IPAlabel{mdraw_image_text} @endlatexonly   */
2041
2042 /***
2043     @errors
2044     @c MERROR_RANGE
2045
2046     @seealso
2047     mdraw_text ()  */
2048
2049 int
2050 mdraw_image_text (MFrame *frame, MDrawWindow win, int x, int y,
2051                   MText *mt, int from, int to)
2052 {
2053   MDrawControl control;
2054
2055   M_CHECK_WRITABLE (frame, MERROR_DRAW, -1);
2056   memset (&control, 0, sizeof control);
2057   control.as_image = 1;
2058   return draw_text (frame, win, x, y, mt, from, to, &control);
2059 }
2060
2061 /*=*/
2062
2063 /***en
2064     @brief Draw an M-text on a window with fine control.
2065
2066     The mdraw_text_with_control () function draws the text between
2067     $FROM and $TO of M-text $MT on windows $WIN of frame $FRAME at
2068     coordinate ($X, $Y).
2069
2070     The way to draw a text is the same as in mdraw_text () except that
2071     this function also follows what specified in the drawing control
2072     object $CONTROL.
2073
2074     For instance, if <two_dimensional> of $CONTROL is nonzero, this
2075     function draw an M-text 2-dimensionally, i.e., newlines in M-text
2076     breaks lines and the following characters are drawn in the next
2077     line.  See the documentation of the structure @ MDrawControl for
2078     more detail.  */
2079
2080 /***ja
2081     @brief ¥Ç¥£¥¹¥×¥ì¥¤¤ËM-text ¤òÉÁ¤¯¡Ê¾ÜºÙ¤ÊÀ©¸æ¤Ä¤­¡Ë.
2082
2083     ´Ø¿ô mdraw_text_with_control () ¤Ï¡¢¥Õ¥ì¡¼¥à $FRAME ¤Î¥¦¥£¥ó¥É¥¦ 
2084     $WIN ¤ÎºÂɸ ($X, $Y) ¤Ë¡¢M-text $MT ¤Î $FROM ¤«¤é $TO ¤Þ¤Ç¤Î¥Æ¥­¥¹
2085     ¥È¤òÉÁ¤¯¡£
2086
2087     ¥Æ¥­¥¹¥È¤ÎÉÁ²èÊýË¡¤Ï mdraw_text () ¤È¤Û¤ÜƱ¤¸¤Ç¤¢¤ë¤¬¡¢¤³¤Î´Ø¿ô¤Ï
2088     ÉÁ²èÀ©¸æÍѤΥª¥Ö¥¸¥§¥¯¥È $CONTROL ¤Ç¤Î»Ø¼¨¤Ë¤â½¾¤¦ÅÀ¤¬°Û¤Ê¤Ã¤Æ¤¤¤ë¡£
2089
2090     ¤¿¤È¤¨¤Ð $CONTROL ¤Î <two_dimensional> ¤¬¥¼¥í¤Ç¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô
2091     ¤ÏM-text ¤ò2¼¡¸µÅª¤ËÉÁ¤¯¡£¤¹¤Ê¤ï¤Á M-text Ãæ¤Î²þ¹Ô¤Ç¹Ô¤ò²þ¤á¡¢Â³¤¯
2092     Ê¸»ú¤Ï¼¡¤Î¹Ô¤ËÉÁ¤¯¡£¾ÜºÙ¤Ï¹½Â¤ÂΠ@ MDrawControl ¤ÎÀâÌÀ¤ò»²¾È¤¹¤ë¤³
2093     ¤È¡£*/
2094
2095 int
2096 mdraw_text_with_control (MFrame *frame, MDrawWindow win, int x, int y,
2097                          MText *mt, int from, int to, MDrawControl *control)
2098 {
2099   M_CHECK_WRITABLE (frame, MERROR_DRAW, -1);
2100   return draw_text (frame, win, x, y, mt, from, to, control);
2101 }
2102
2103 /*=*/
2104
2105 /***en
2106     @brief Compute text pixel width.
2107
2108     The mdraw_text_extents () function computes the width of text
2109     between $FROM and $TO of M-text $MT when it is drawn on a window
2110     of frame $FRAME using the mdraw_text_with_control () function with
2111     the drawing control object $CONTROL.
2112
2113     If $OVERALL_INK_RETURN is not @c NULL, this function also computes
2114     the bounding box of character ink of the M-text, and stores the
2115     results in the members of the structure pointed to by
2116     $OVERALL_INK_RETURN.  If the M-text has a face specifying a
2117     surrounding box, the box is included in the bounding box.
2118
2119     If $OVERALL_LOGICAL_RETURN is not @c NULL, this function also
2120     computes the bounding box that provides mininum spacing to other
2121     graphical features (such as surrounding box) for the M-text, and
2122     stores the results in the members of the structure pointed to by
2123     $OVERALL_LOGICAL_RETURN.
2124
2125     If $OVERALL_LINE_RETURN is not @c NULL, this function also
2126     computes the bounding box that provides mininum spacing to the
2127     other M-text drawn, and stores the results in the members of the
2128     structure pointed to by $OVERALL_LINE_RETURN.  This is a union of
2129     $OVERALL_INK_RETURN and $OVERALL_LOGICAL_RETURN if the members
2130     min_line_ascent, min_line_descent, max_line_ascent, and
2131     max_line_descent of $CONTROL are all zero.
2132
2133     @return
2134     This function returns the width of the text to be drawn in the
2135     unit of pixels.  If $CONTROL->two_dimensional is nonzero and the
2136     text is drawn in multiple physical lines, it returns the width of
2137     the widest line.  If an error occurs, it returns -1 and assigns an
2138     error code to the external variable #merror_code.  */
2139
2140
2141 /***ja 
2142     @brief ¥Æ¥­¥¹¥È¤ÎÉý¡Ê¥Ô¥¯¥»¥ëñ°Ì¡Ë¤ò·×»»¤¹¤ë.
2143
2144     ´Ø¿ô mdraw_text_extents () ¤Ï¡¢´Ø¿ô mdraw_text_with_control () ¤¬
2145     ÉÁ²èÀ©¸æ¥ª¥Ö¥¸¥§¥¯¥È $CONTROL ¤òÍѤ¤¤Æ M-text $MT ¤Î $FROM ¤«¤é $TO 
2146     ¤Þ¤Ç¤ò¥Õ¥ì¡¼¥à $FRAME ¤Ëɽ¼¨¤¹¤ëºÝ¤ËɬÍפȤʤëÉý¤òÊÖ¤¹¡£
2147
2148     $OVERALL_INK_RETURN ¤¬ @c NULL ¤Ç¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï M-text ¤Îʸ
2149     »ú¤Î¥¤¥ó¥¯¤Î¥Ð¥¦¥ó¥Ç¥£¥ó¥°¥Ü¥Ã¥¯¥¹¤â·×»»¤·¡¢$OVERALL_INK_RETURN ¤¬
2150     »Ø¤¹¹½Â¤ÂΤΥá¥ó¥Ð¤Ë¤½¤Î·ë²Ì¤òÀßÄꤹ¤ë¡£M-text ¤Ë°Ï¤ßÏÈ(surrounding box)
2151     ¤ò»ØÄꤹ¤ë¥Õ¥§¡¼¥¹¤¬¤¢¤ì¤Ð¡¢¤½¤ì¤â¥Ð¥¦¥ó¥Ç¥£¥ó¥°¥Ü¥Ã¥¯¥¹¤Ë´Þ¤à¡£
2152
2153     $OVERALL_LOGICAL_RETURN ¤¬ @c NULL ¤Ç¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï M-text 
2154     ¤È¾¤Î graphical feature ¡Ê°Ï¤ßÏȤʤɡˤȤδ֤κǾ®¤Î¥¹¥Ú¡¼¥¹¤ò¼¨
2155     ¤¹¥Ð¥¦¥ó¥Ç¥£¥ó¥°¥Ü¥Ã¥¯¥¹¤â·×»»¤·¡¢$OVERALL_LOGICAL_RETURN ¤¬»Ø¤¹¹½
2156     Â¤ÂΤΥá¥ó¥Ð¤Ë¤½¤Î·ë²Ì¤òÀßÄꤹ¤ë¡£
2157
2158     $OVERALL_LINE_RETURN ¤¬ @c NULL ¤Ç¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï¾¤Î M-text 
2159     ¤È¤Î´Ö¤ÎºÇ¾®¤Î¥¹¥Ú¡¼¥¹¤ò¼¨¤¹¥Ð¥¦¥ó¥Ç¥£¥ó¥°¥Ü¥Ã¥¯¥¹¤â·×»»¤·¡¢
2160     $OVERALL_LINE_RETURN ¤¬»Ø¤¹¹½Â¤ÂΤΥá¥ó¥Ð¤Ë¤½¤Î·ë²Ì¤òÀßÄꤹ¤ë¡£¥ª
2161     ¥Ö¥¸¥§¥¯¥È $CONTROL ¤Î¥á¥ó¥Ð min_line_ascent, min_line_descent,
2162     max_line_ascent, max_line_descent ¤¬¤¹¤Ù¤Æ0¤Î»þ¤Ë¤Ï¡¢¤³¤ÎÃͤϠ
2163     $OVERALL_INK_RETURN ¤È$OVERALL_LOGICAL_RETURN ¤ÎϤȤʤ롣
2164
2165     @return ¤³¤Î´Ø¿ô¤Ïɽ¼¨¤ËɬÍפʥƥ­¥¹¥È¤ÎÉý¤ò¥Ô¥¯¥»¥ëñ°Ì¤ÇÊÖ¤¹¡£
2166     $CONTROL->two_dimensional ¤¬0¤Ç¤Ê¤¯¡¢¥Æ¥­¥¹¥È¤¬Ê£¿ô¤Î¹Ô¤ËÅϤäÆÉÁ
2167     ¤«¤ì¤ë¾ì¹ç¤Ë¤Ï¡¢ºÇÂç¤ÎÉý¤òÊÖ¤¹¡£¥¨¥é¡¼¤¬À¸¤¸¤¿¾ì¹ç¤Ï -1 ¤òÊÖ¤·¡¢³°
2168     ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
2169
2170     @latexonly \IPAlabel{mdraw_text_extents} @endlatexonly  */
2171
2172 /***
2173     @errors
2174     @c MERROR_RANGE  */
2175
2176 int
2177 mdraw_text_extents (MFrame *frame,
2178                     MText *mt, int from, int to, MDrawControl *control,
2179                     MDrawMetric *overall_ink_return,
2180                     MDrawMetric *overall_logical_return,
2181                     MDrawMetric *overall_line_return)
2182 {
2183   MGlyphString *gstring;
2184   int y = 0;
2185   int width, rbearing;
2186
2187   ASSURE_CONTROL (control);
2188   M_CHECK_POS_X (mt, from, -1);
2189   if (to > mtext_nchars (mt) + (control->cursor_width != 0))
2190     to = mtext_nchars (mt) + (control->cursor_width != 0);
2191   else if (to < from)
2192     to = from;
2193
2194   gstring = get_gstring (frame, mt, from, to, control);
2195   if (! gstring)
2196     MERROR (MERROR_DRAW, -1);
2197   width = gstring_width (gstring, from, to, &rbearing);
2198   if (overall_ink_return)
2199     {
2200       overall_ink_return->y = - gstring->physical_ascent;
2201       overall_ink_return->x = gstring->lbearing;
2202     }
2203   if (overall_logical_return)
2204     {
2205       overall_logical_return->y = - gstring->ascent;
2206       overall_logical_return->x = 0;
2207     }
2208   if (overall_line_return)
2209     {
2210       overall_line_return->y = - gstring->line_ascent;
2211       overall_line_return->x = gstring->lbearing;
2212     }
2213
2214   for (from = gstring->to; from < to; from = gstring->to)
2215     {
2216       int this_width, this_rbearing;
2217
2218       y += gstring->line_descent;
2219       M17N_OBJECT_UNREF (gstring->top);
2220       gstring = get_gstring (frame, mt, from, to, control);
2221       this_width = gstring_width (gstring, from, to, &this_rbearing);
2222       y += gstring->line_ascent;
2223       if (width < this_width)
2224         width = this_width;
2225       if (rbearing < this_rbearing)
2226         rbearing = this_rbearing;
2227     }
2228   if (overall_ink_return)
2229     {
2230       overall_ink_return->width = rbearing;
2231       overall_ink_return->height
2232         = y + gstring->physical_descent - overall_ink_return->y;
2233     }
2234   if (overall_logical_return)
2235     {
2236       overall_logical_return->width = width;
2237       overall_logical_return->height
2238         = y + gstring->descent - overall_logical_return->y;
2239     }
2240   if (overall_line_return)
2241     {
2242       overall_line_return->width = MAX (width, rbearing);
2243       overall_line_return->height
2244         = y + gstring->line_descent - overall_line_return->y;
2245     }
2246
2247   M17N_OBJECT_UNREF (gstring->top);
2248   return width;
2249 }
2250
2251 /*=*/
2252
2253 /***en
2254     @brief Compute the text dimensions of each character of M-text.
2255
2256     The mdraw_text_per_char_extents () function computes the drawn
2257     metric of each character between $FROM and $TO of M-text $MT
2258     assuming that they are drawn on a window of frame $FRAME using the
2259     mdraw_text_with_control () function with the drawing control
2260     object $CONTROL.
2261
2262     $ARRAY_SIZE specifies the size of $INK_ARRAY_RETURN and
2263     $LOGICAL_ARRAY_RETURN.  Each successive element of
2264     $INK_ARRAY_RETURN and $LOGICAL_ARRAY_RETURN are set to the drawn
2265     ink and logical metrics of successive characters respectively,
2266     relative to the drawing origin of the M-text.  The number of
2267     elements of $INK_ARRAY_RETURN and $LOGICAL_ARRAY_RETURN that have
2268     been set is returned to $NUM_CHARS_RETURN.
2269
2270     If $ARRAY_SIZE is too small to return all metrics, the function
2271     returns -1 and store the requested size in $NUM_CHARS_RETURN.
2272     Otherwise, it returns zero.
2273
2274     If pointer $OVERALL_INK_RETURN and $OVERALL_LOGICAL_RETURN are not
2275     @c NULL, this function also computes the metrics of the overall
2276     text and stores the results in the members of the structure
2277     pointed to by $OVERALL_INK_RETURN and $OVERALL_LOGICAL_RETURN.
2278
2279     If $CONTROL->two_dimensional is nonzero, this function computes
2280     only the metrics of characters in the first line.  */
2281 /***ja
2282     @brief  M-text ¤Î³Æʸ»ú¤Îɽ¼¨ÈϰϤò·×»»¤¹¤ë.
2283
2284     ´Ø¿ô mdraw_text_per_char_extents () ¤Ï¡¢´Ø¿ô 
2285     mdraw_text_with_control () ¤¬ÉÁ²èÀ©¸æ¥ª¥Ö¥¸¥§¥¯¥È $CONTROL ¤òÍѤ¤
2286     ¤Æ M-text $MT ¤Î $FROM ¤«¤é $TO ¤Þ¤Ç¤ò¥Õ¥ì¡¼¥à $FRAME ¤Ëɽ¼¨¤¹¤ëºÝ
2287     ¤Î³Æʸ»ú¤Î¥µ¥¤¥º¤ò·×»»¤¹¤ë¡£
2288
2289     $ARRAY_SIZE ¤Ë¤è¤Ã¤Æ $INK_ARRAY_RETURN ¤È$LOGICAL_ARRAY_RETURN ¤Î
2290     ¥µ¥¤¥º¤ò»ØÄꤹ¤ë¡£$INK_ARRAY_RETURN ¤È$LOGICAL_ARRAY_RETURN ¤Î³ÆÍ×
2291     ÁǤϡ¢¤½¤ì¤¾¤ìʸ»ú¤ÎÉÁ²è¥¤¥ó¥¯¤ÈÏÀÍý¥µ¥¤¥º¡ÊM-text¤Îɽ¼¨¸¶ÅÀ¤«¤é¤Î
2292     ÁêÂаÌÃ͡ˤˤè¤Ã¤Æ½ç¤ËËä¤á¤é¤ì¤ë¡£ÀßÄꤵ¤ì¤¿ $INK_ARRAY_RETURN ¤È 
2293     $LOGICAL_ARRAY_RETURN ¤ÎÍ×ÁǤοô¤Ï¡¢$NUM_CHARS_RETURN ¤ËÌᤵ¤ì¤ë¡£
2294    
2295     $ARRAY_SIZE ¤¬¤¹¤Ù¤Æ¤ÎÀ£Ë¡¤òÌ᤻¤Ê¤¤¤Û¤É¾®¤µ¤¤¾ì¹ç¤Ë¤Ï¡¢´Ø¿ô¤Ï -1 
2296     ¤òÊÖ¤·¡¢É¬ÍפÊÂ礭¤µ¤ò $NUM_CHARS_RETURN ¤ËÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð 0 
2297     ¤òÊÖ¤¹¡£
2298
2299     ¥Ý¥¤¥ó¥¿ $OVERALL_INK_RETURN ¤È $OVERALL_LOGICAL_RETURN ¤¬@c NULL 
2300     ¤Ç¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï¥Æ¥­¥¹¥ÈÁ´ÂΤΥµ¥¤¥º¤â·×»»¤·¡¢·ë²Ì¤ò
2301     $OVERALL_INK_RETURN ¤È $OVERALL_LOGICAL_RETURN ¤Ç»Ø¤µ¤ì¤ë¹½Â¤¤Î¥á
2302     ¥ó¥Ð¤ËÊݸ¤¹¤ë¡£
2303
2304     $CONTROL->two_dimensional ¤¬0¤Ç¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤ÏºÇ½é¤Î¹Ô¤Îʸ»ú
2305     ¤Î¥µ¥¤¥º¤À¤±¤ò·×»»¤¹¤ë¡£ */
2306
2307 int
2308 mdraw_text_per_char_extents (MFrame *frame,
2309                              MText *mt, int from, int to,
2310                              MDrawControl *control,
2311                              MDrawMetric *ink_array_return,
2312                              MDrawMetric *logical_array_return,
2313                              int array_size,
2314                              int *num_chars_return,
2315                              MDrawMetric *overall_ink_return,
2316                              MDrawMetric *overall_logical_return)
2317 {
2318   MGlyphString *gstring;
2319   MGlyph *g;
2320   int x;
2321
2322   ASSURE_CONTROL (control);
2323   *num_chars_return = to - from;
2324   if (array_size < *num_chars_return)
2325     MERROR (MERROR_DRAW, -1);
2326   if (overall_logical_return)
2327     memset (overall_logical_return, 0, sizeof (MDrawMetric));
2328   if (overall_ink_return)
2329     memset (overall_ink_return, 0, sizeof (MDrawMetric));
2330
2331   M_CHECK_RANGE (mt, from, to, -1, 0);
2332   gstring = get_gstring (frame, mt, from, to, control);
2333   if (! gstring)
2334     {
2335       *num_chars_return = 0;
2336       return 0;
2337     }
2338
2339   for (g = MGLYPH (1), x = 0; g->type != GLYPH_ANCHOR; g++)
2340     if (g->pos >= from && g->pos < to)
2341       {
2342         int start = g->pos;
2343         int end = g->to;
2344         int width = g->width;
2345         int lbearing = g->lbearing;
2346         int rbearing = g->rbearing;
2347         int ascent = g->ascent;
2348         int descent = g->descent;
2349         int logical_ascent;
2350         int logical_descent;
2351
2352         if (g->rface->rfont)
2353           {
2354             logical_ascent = g->rface->rfont->ascent;
2355             logical_descent = g->rface->rfont->descent;
2356           }
2357         else
2358           {
2359             logical_ascent = g->rface->ascent;
2360             logical_descent = g->rface->descent;
2361           }
2362         for (g++; g->type != GLYPH_ANCHOR && g->pos == start; g++)
2363           {
2364             if (lbearing < width + g->lbearing)
2365               lbearing = width + g->lbearing;
2366             if (rbearing < width + g->rbearing)
2367               rbearing = width + g->rbearing;
2368             width += g->width;
2369             if (ascent < g->ascent)
2370               ascent = g->ascent;
2371             if (descent < g->descent)
2372               descent = g->descent;
2373           }
2374
2375         if (end > to)
2376           end = to;
2377         while (start < end)
2378           {
2379             if (ink_array_return)
2380               {
2381                 ink_array_return[start - from].x = x + lbearing;
2382                 ink_array_return[start - from].y = - ascent;
2383                 ink_array_return[start - from].width = rbearing - lbearing;
2384                 ink_array_return[start - from].height = ascent + descent;
2385               }
2386             if (logical_array_return)
2387               {
2388                 logical_array_return[start - from].x = x;
2389                 logical_array_return[start - from].y = - logical_descent;
2390                 logical_array_return[start - from].height
2391                   = logical_ascent + logical_descent;
2392                 logical_array_return[start - from].width = width;
2393               }
2394             start++;
2395           }
2396         x += width;
2397         g--;
2398       }
2399
2400   if (overall_ink_return)
2401     {
2402       overall_ink_return->y = - gstring->line_ascent;
2403       overall_ink_return->x = gstring->lbearing;
2404       overall_ink_return->width = x - gstring->lbearing;
2405       overall_ink_return->height = gstring->height;
2406     }
2407   if (overall_logical_return)
2408     {
2409       overall_logical_return->y = - gstring->ascent;
2410       overall_logical_return->x = 0;
2411       overall_logical_return->width = x;
2412       overall_logical_return->height = gstring->ascent + gstring->descent;
2413     }
2414
2415   M17N_OBJECT_UNREF (gstring->top);
2416   return 0;
2417 }
2418
2419 /*=*/
2420
2421 /***en
2422     @brief Return the character position nearest to the coordinates.
2423
2424     The mdraw_coordinates_position () function checks which character
2425     is to be drawn at coordinate ($X, $Y) when the text between $FROM
2426     and $TO of M-text $MT is drawn at the coordinate (0, 0) using the
2427     mdraw_text_with_control () function with the drawing control
2428     object $CONTROL.  Here, the character position means the number of
2429     characters that precede the character in question in $MT, that is,
2430     the character position of the first character is 0.
2431
2432     $FRAME is used only to get the default face information.
2433
2434     @return
2435     If the glyph image of a character covers coordinate ($X, $Y),
2436     mdraw_coordinates_position () returns the character position of
2437     that character.\n\n
2438     If $Y is less than the minimum Y-coordinate of the drawn area, it
2439     returns $FROM.\n\n\n
2440     If $Y is greater than the maximum Y-coordinate of the drawn area,
2441     it returns $TO.\n\n\n
2442     If $Y fits in with the drawn area but $X is less than the minimum
2443     X-coordinate, it returns the character position of the first
2444     character drawn on the line $Y.\n\n\n
2445     If $Y fits in with the drawn area but $X is greater than the
2446     maximum X-coordinate, it returns the character position of the
2447     last character drawn on the line $Y.  */
2448
2449 /***ja
2450     @brief »ØÄꤷ¤¿ºÂɸ¤ËºÇ¤â¶á¤¤Ê¸»ú¤Îʸ»ú°ÌÃÖ¤òÆÀ¤ë.
2451
2452     ´Ø¿ô mdraw_coordinates_position () ¤Ï¡¢´Ø¿ô 
2453     mdraw_text_with_control () ¤¬ÉÁ²èÀ©¸æ¥ª¥Ö¥¸¥§¥¯¥È $CONTROL ¤òÍѤ¤
2454     ¤ÆM-text $MT ¤Î $FROM ¤«¤é $TO ¤Þ¤Ç¤òºÂɸ (0, 0) ¤òµ¯ÅÀ¤È¤·¤ÆÉÁ²è
2455     ¤·¤¿¾ì¹ç¤Ë¡¢ºÂɸ ($X, $Y) ¤ËÉÁ²è¤µ¤ì¤ëʸ»ú¤Îʸ»ú°ÌÃÖ¤òÊÖ¤¹¡£¤³¤³¤Ç
2456     Ê¸»ú°ÌÃ֤Ȥϡ¢Åö³º M-text Ãæ¤Ë¤ª¤¤¤Æ¤½¤Îʸ»ú¤¬ºÇ½é¤«¤é²¿ÈÖÌܤ«¤ò¼¨
2457     ¤¹À°¿ô¤Ç¤¢¤ë¡£¤¿¤À¤·ºÇ½é¤Îʸ»ú¤Îʸ»ú°ÌÃÖ¤Ï0¤È¤¹¤ë¡£
2458
2459     $FRAME ¤Ï¥Ç¥Õ¥©¥ë¥È¤Î¥Õ¥§¡¼¥¹¤Î¾ðÊó¤òÆÀ¤ë¤¿¤á¤À¤±¤ËÍѤ¤¤é¤ì¤ë¡£
2460
2461     @return
2462     ºÂɸ ($X, $Y) ¤¬¤¢¤ëʸ»ú¤Î¥°¥ê¥Õ¤Çʤ¤ï¤ì¤ë¾ì¹ç¡¢ ´Ø¿ô 
2463     mdraw_coordinates_position () ¤Ï¤½¤Îʸ»ú¤Îʸ»ú°ÌÃÖ¤òÊÖ¤¹¡£
2464
2465     ¤â¤· $Y ¤¬ÉÁ²èÎΰè¤ÎºÇ¾®YºÂɸ¤è¤ê¤â¾®¤µ¤¤¤Ê¤é¤Ð $FROM ¤òÊÖ¤¹¡£
2466
2467     ¤â¤· $Y ¤¬ÉÁ²èÎΰè¤ÎºÇÂçYºÂɸ¤è¤ê¤âÂ礭¤¤¤Ê¤é¤Ð $TO ¤òÊÖ¤¹¡£
2468
2469     ¤â¤· $Y ¤¬ÉÁ²èÎΰè¤Ë¾è¤Ã¤Æ¤¤¤Æ¤«¤Ä $X ¤¬ÉÁ²èÎΰè¤ÎºÇ¾®XºÂɸ¤è¤ê¤â
2470     ¾®¤µ¤¤¾ì¹ç¤Ï¡¢Ä¾Àþ y = $Y ¾å¤ËÉÁ²è¤µ¤ì¤ëºÇ½é¤Îʸ»ú¤Îʸ»ú°ÌÃÖ¤òÊÖ¤¹¡£
2471
2472     ¤â¤· $Y ¤¬ÉÁ²èÎΰè¤Ë¾è¤Ã¤Æ¤¤¤Æ¤«¤Ä $X ¤¬ÉÁ²èÎΰè¤ÎºÇÂçXºÂɸ¤è¤ê¤â
2473     Â礭¤¤¾ì¹ç¤Ï¡¢Ä¾Àþ y = $Y ¾å¤ËÉÁ²è¤µ¤ì¤ëºÇ¸å¤Îʸ»ú¤Îʸ»ú°ÌÃÖ¤òÊÖ¤¹¡£ */
2474
2475 int
2476 mdraw_coordinates_position (MFrame *frame, MText *mt, int from, int to,
2477                             int x_offset, int y_offset, MDrawControl *control)
2478 {
2479   MGlyphString *gstring;
2480   int y = 0;
2481   int width;
2482   MGlyph *g;
2483
2484   M_CHECK_POS_X (mt, from, -1);
2485   if (to > mtext_nchars (mt) + (control->cursor_width != 0))
2486     to = mtext_nchars (mt) + (control->cursor_width != 0);
2487   else if (to < from)
2488     to = from;
2489
2490   if (from == to)
2491     return from;
2492   ASSURE_CONTROL (control);
2493   gstring = get_gstring (frame, mt, from, to, control);
2494   while (y + gstring->line_descent <= y_offset
2495          && gstring->to < to)
2496     {
2497       from = gstring->to;
2498       y += gstring->line_descent;
2499       M17N_OBJECT_UNREF (gstring->top);
2500       gstring = get_gstring (frame, mt, from, to, control);
2501       y += gstring->line_ascent;
2502     }
2503
2504   /* Accumulate width of glyphs in WIDTH until it exceeds X. */
2505   if (! control->orientation_reversed)
2506     {
2507       width = gstring->indent;
2508       for (g = MGLYPH (1); g->type != GLYPH_ANCHOR; g++)
2509         if (g->pos >= from && g->pos < to)
2510           {
2511             width += g->width;
2512             if (width > x_offset)
2513               break;
2514           }
2515     }
2516   else
2517     {
2518       width = - gstring->indent;
2519       for (g = MGLYPH (gstring->used - 2); g->type != GLYPH_ANCHOR; g--)
2520         if (g->pos >= from && g->pos < to)
2521           {
2522             width -= g->width;
2523             if (width < x_offset)
2524               break;
2525           }
2526     }
2527   if (g->type == GLYPH_ANCHOR
2528       && control->two_dimensional
2529       && g[-1].c == '\n')
2530     g--;
2531   from = g->pos;
2532   M17N_OBJECT_UNREF (gstring->top);
2533
2534   return from;
2535 }
2536
2537 /*=*/
2538
2539 /***en
2540     @brief Compute information about a glyph.
2541
2542     The mdraw_glyph_info () function computes information about a
2543     glyph that covers a character at position $POS of the M-text $MT
2544     assuming that the text is drawn from the character at $FROM of $MT
2545     on a window of frame $FRAME using the mdraw_text_with_control ()
2546     function with the drawing control object $CONTROL.
2547
2548     The information is stored in the members of $INFO.  */
2549 /***ja
2550     @brief ¥°¥ê¥Õ¤Ë´Ø¤¹¤ë¾ðÊó¤ò·×»»¤¹¤ë.
2551
2552     ´Ø¿ô mdraw_glyph_info () ¤Ï¡¢´Ø¿ô mdraw_text_with_control () ¤¬ÉÁ
2553     ²èÀ©¸æ¥ª¥Ö¥¸¥§¥¯¥È $CONTROL ¤òÍѤ¤¤ÆM-text $MT ¤Î $FROM ¤«¤é $TO 
2554     ¤Þ¤Ç¤ò¥Õ¥ì¡¼¥à $FRAME ¤ËÉÁ²è¤·¤¿¾ì¹ç¡¢M-text ¤Îʸ»ú°ÌÃÖ $POS ¤Îʸ
2555     »ú¤òʤ¤¦¥°¥ê¥Õ¤Ë´Ø¤¹¤ë¾ðÊó¤ò·×»»¤¹¤ë¡£
2556
2557     ¾ðÊó¤Ï$INFO ¤Î¥á¥ó¥Ð¤ËÊÝ»ý¤µ¤ì¤ë¡£  */
2558
2559 /***
2560     @seealso
2561     MDrawGlyphInfo
2562 */
2563
2564 int
2565 mdraw_glyph_info (MFrame *frame, MText *mt, int from, int pos,
2566                   MDrawControl *control, MDrawGlyphInfo *info)
2567 {
2568   MGlyphString *gstring;
2569   MGlyph *g;
2570   int y = 0;
2571
2572   M_CHECK_RANGE_X (mt, from, pos, -1);
2573
2574   ASSURE_CONTROL (control);
2575   gstring = get_gstring (frame, mt, from, pos + 1, control);
2576   if (! gstring)
2577     MERROR (MERROR_DRAW, -1);
2578   while (gstring->to <= pos)
2579     {
2580       y += gstring->line_descent;
2581       M17N_OBJECT_UNREF (gstring->top);
2582       gstring = get_gstring (frame, mt, gstring->to, pos + 1, control);
2583       y += gstring->line_ascent;
2584     }
2585   info->line_from = gstring->from;
2586   if (info->line_from < from)
2587     info->line_from = from;
2588   info->line_to = gstring->to;
2589
2590   info->y = y;
2591   if (! control->orientation_reversed)
2592     {
2593       info->x = gstring->indent;
2594       for (g = MGLYPH (1); g->pos > pos || g->to <= pos; g++)
2595         info->x += g->width;
2596     }
2597   else
2598     {
2599       info->x = - gstring->indent;
2600       for (g = MGLYPH (gstring->used - 2); g->pos > pos || g->to <= pos; g--)
2601         info->x -= g->width;
2602       while (g[-1].to == g->to)
2603         g--;
2604     }
2605   info->from = g->pos;
2606   info->to = g->to;
2607   info->metrics.x = g->lbearing;
2608   info->metrics.y = - gstring->line_ascent;
2609   info->metrics.height = gstring->height;
2610   info->metrics.width = - g->lbearing + g->width;
2611   if (g->rface->rfont)
2612     info->font = &g->rface->rfont->font;
2613   else
2614     info->font = NULL;
2615   /* info->logical_width is calculated later.  */
2616
2617   if (info->from > info->line_from)
2618     {
2619       /* The logically previous glyph is on this line.  */
2620       MGlyph *g_tmp = find_glyph_in_gstring (gstring, info->from - 1, 1);
2621
2622       info->prev_from = g_tmp->pos;
2623     }
2624   else if (info->line_from > 0)
2625     {
2626       /* The logically previous glyph is on the previous line.  */
2627       MGlyphString *gst = get_gstring (frame, mt, gstring->from - 1,
2628                                        gstring->from, control);
2629       MGlyph *g_tmp = find_glyph_in_gstring (gst, info->from - 1, 1);
2630
2631       info->prev_from = g_tmp->pos;
2632       M17N_OBJECT_UNREF (gst->top);
2633     }
2634   else
2635     info->prev_from = -1;
2636
2637   if (GLYPH_INDEX (g) > 1)
2638     info->left_from = g[-1].pos, info->left_to = g[-1].to;
2639   else if (! control->orientation_reversed)
2640     {
2641       if (info->line_from > 0)
2642         {
2643           MGlyph *g_tmp;
2644           MGlyphString *gst;
2645           int p = gstring->from - 1;
2646
2647           gst = get_gstring (frame, mt, p, gstring->from, control);
2648           g_tmp = gst->glyphs + (gst->used - 2);
2649           info->left_from = g_tmp->pos, info->left_to = g_tmp->to;
2650           M17N_OBJECT_UNREF (gst->top);
2651         }
2652       else
2653         info->left_from = info->left_to = -1;
2654     }
2655   else
2656     {
2657       if (gstring->to + (control->cursor_width == 0) <= mtext_nchars (mt))
2658         {
2659           MGlyph *g_tmp;
2660           MGlyphString *gst;
2661           int p = gstring->to;
2662
2663           gst = get_gstring (frame, mt, p, p + 1, control);
2664           g_tmp = gst->glyphs + (gst->used - 2);
2665           info->left_from = g_tmp->pos, info->left_to = g_tmp->to;
2666           M17N_OBJECT_UNREF (gst->top);
2667         }
2668       else
2669         info->left_from = info->left_to = -1;
2670     }
2671
2672   if (info->to < gstring->to)
2673     {
2674       /* The logically next glyph is on this line.   */
2675       MGlyph *g_tmp = find_glyph_in_gstring (gstring, info->to, 0);
2676
2677       info->next_to = g_tmp->to;
2678     }
2679   else if (info->to + (control->cursor_width == 0) <= mtext_nchars (mt))
2680     {
2681       /* The logically next glyph is on the next line.   */
2682       int p = info->to;
2683       MGlyphString *gst = get_gstring (frame, mt, p, p + 1, control);
2684       MGlyph *g_tmp = find_glyph_in_gstring (gst, p, 0);
2685
2686       info->next_to = g_tmp->to;
2687       M17N_OBJECT_UNREF (gst->top);
2688     }
2689   else
2690     info->next_to = -1;
2691
2692   for (info->logical_width = (g++)->width;
2693        g->pos == pos && g->type != GLYPH_ANCHOR;
2694        info->metrics.width += g->width, info->logical_width += (g++)->width);
2695   info->metrics.width += g[-1].rbearing - g[-1].width;
2696
2697   if (g->type != GLYPH_ANCHOR)
2698     info->right_from = g->pos, info->right_to = g->to;
2699   else if (! control->orientation_reversed)
2700     {
2701       if (gstring->to + (control->cursor_width == 0) <= mtext_nchars (mt))
2702         {
2703           pos = gstring->to;
2704           M17N_OBJECT_UNREF (gstring->top);
2705           gstring = get_gstring (frame, mt, pos, pos + 1, control);
2706           g = MGLYPH (1);
2707           info->right_from = g->pos, info->right_to = g->to;
2708         }
2709       else
2710         info->right_from = info->right_to = -1;
2711     }
2712   else
2713     {
2714       if (info->line_from > 0)
2715         {
2716           pos = gstring->from - 1;
2717           M17N_OBJECT_UNREF (gstring->top);
2718           gstring = get_gstring (frame, mt, pos, pos + 1, control);
2719           g = MGLYPH (1);
2720           info->right_from = g->pos, info->right_to = g->to;
2721         }
2722       else
2723         info->right_from = info->right_to = -1;
2724     }
2725
2726   M17N_OBJECT_UNREF (gstring->top);
2727   return 0;
2728 }
2729
2730 /*=*/
2731
2732 /***en
2733     @brief Compute information about glyph sequence.
2734
2735     The mdraw_glyph_list () function computes information about glyphs
2736     corresponding to the text between $FROM and $TO of M-text $MT when
2737     it is drawn on a window of frame $FRAME using the
2738     mdraw_text_with_control () function with the drawing control
2739     object $CONTROL.  $GLYPHS is an array of objects to store the
2740     information, and $ARRAY_SIZE is the array size.
2741
2742     If $ARRAY_SIZE is large enough to cover all glyphs, it stores the
2743     number of actually filled elements in the place pointed by
2744     $NUM_GLYPHS_RETURN, and returns 0.
2745
2746     Otherwise, it stores the required array size in the place pointed
2747     by $NUM_GLYPHS_RETURN, and returns -1.  */
2748
2749 /***ja
2750     @brief ¥°¥ê¥ÕÎó¤Ë´Ø¤¹¤ë¾ðÊó¤ò·×»»¤¹¤ë.
2751
2752     ´Ø¿ô mdraw_glyph_list () ¤Ï¡¢´Ø¿ô mdraw_text_with_control () ¤¬ÉÁ²è
2753     À©¸æ¥ª¥Ö¥¸¥§¥¯¥È $CONTROL ¤òÍѤ¤¤ÆM-text $MT ¤Î $FROM ¤«¤é $TO ¤Þ¤Ç
2754     ¤ò¥Õ¥ì¡¼¥à $FRAME ¤ËÉÁ²è¤·¤¿¾ì¹ç¤Î¡¢³Æ¥°¥ê¥Õ¤Î¾ðÊó¤ò $GLYPHS ¤¬»Ø¤¹
2755     ÇÛÎó¤Ë³ÊǼ¤¹¤ë¡£ $ARRAY_SIZE ¤Ï¤½¤ÎÇÛÎó¤Î¥µ¥¤¥º¤Ç¤¢¤ë¡£
2756
2757     ¤â¤· $ARRAY_SIZE ¤¬¤¹¤Ù¤Æ¤Î¥°¥ê¥Õ¤Ë¤Ä¤¤¤Æ¤Î¾ðÊó¤ò³ÊǼ¤¹¤ë¤Î¤Ë½½Ê¬¤Ç
2758     ¤¢¤ì¤Ð¡¢ $NUM_GLYPHS_RETURN ¤¬»Ø¤¹¾ì½ê¤Ë¼ÂºÝ¤ËËä¤á¤¿Í×ÁǤοô¤òÀßÄê
2759     ¤· 0 ¤òÊÖ¤¹¡£  */
2760
2761 /***
2762     @seealso
2763     MDrawGlyph
2764 */
2765
2766 int
2767 mdraw_glyph_list (MFrame *frame, MText *mt, int from, int to,
2768                   MDrawControl *control, MDrawGlyph *glyphs,
2769                   int array_size, int *num_glyphs_return)
2770 {
2771   MGlyphString *gstring;
2772   MGlyph *g;
2773   int n;
2774   int pad_width = 0;
2775
2776   ASSURE_CONTROL (control);
2777   *num_glyphs_return = 0;
2778   M_CHECK_RANGE (mt, from, to, -1, 0);
2779   gstring = get_gstring (frame, mt, from, to, control);
2780   if (! gstring)
2781     return -1;
2782   for (g = MGLYPH (1), n = 0; g->type != GLYPH_ANCHOR; g++)
2783     {
2784       if (g->type == GLYPH_BOX
2785           || g->pos < from || g->pos >= to)
2786         continue;
2787       if (g->type == GLYPH_PAD)
2788         {
2789           if (g->left_padding)
2790             pad_width = g->width;
2791           else if (n > 0)
2792             {
2793               pad_width = 0;
2794               glyphs[-1].x_advance += g->width;
2795             }
2796           continue;
2797         }
2798       if (n < array_size)
2799         {
2800           glyphs->from = g->pos;
2801           glyphs->to = g->to;
2802           glyphs->glyph_code = g->code;
2803           glyphs->x_off = g->xoff + pad_width;
2804           glyphs->y_off = g->yoff;
2805           glyphs->lbearing = g->lbearing;
2806           glyphs->rbearing = g->rbearing;
2807           glyphs->ascent = g->ascent;
2808           glyphs->descent = g->descent;
2809           glyphs->x_advance = g->width + pad_width;
2810           glyphs->y_advance = 0;
2811           if (g->rface->rfont)
2812             {
2813               glyphs->font = &g->rface->rfont->font;
2814               glyphs->font_type = g->rface->rfont->type;
2815               glyphs->fontp = g->rface->rfont->fontp;
2816             }
2817           else
2818             {
2819               glyphs->font = NULL;
2820               glyphs->font_type = Mnil;
2821               glyphs->fontp = NULL;
2822             }
2823           pad_width = 0;
2824           glyphs++;
2825         }
2826       n++;
2827     }
2828   M17N_OBJECT_UNREF (gstring->top);
2829
2830   *num_glyphs_return = n;
2831   return (n <= array_size ? 0 : -1);
2832 }
2833
2834 /*=*/
2835
2836 /***en
2837     @brief Draw one or more textitems.
2838
2839     The mdraw_text_items () function draws one or more M-texts on
2840     window $WIN of $FRAME at coordinate ($X, $Y).  $ITEMS is an array
2841     of the textitems to be drawn and $NITEMS is the number of
2842     textimtems in the array.  */
2843
2844 /***ja
2845     @brief textitem ¤òɽ¼¨¤¹¤ë.
2846
2847     ´Ø¿ô mdraw_text_items () ¤Ï¡¢°ì¸Ä°Ê¾å¤Î¥Æ¥­¥¹¥È¥¢¥¤¥Æ¥à¤ò¡¢¥Õ¥ì¡¼
2848     ¥à $FRAME ¤Î¥¦¥£¥ó¥É¥¦ $WIN ¤ÎºÂɸ ($X, $Y) ¤Ëɽ¼¨¤¹¤ë¡£$ITEMS ¤Ï
2849     É½¼¨¤¹¤Ù¤­¥Æ¥­¥¹¥È¥¢¥¤¥Æ¥à¤ÎÇÛÎó¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ê¡¢$NITEMS ¤Ï¤½¤Î
2850     ¸Ä¿ô¤Ç¤¢¤ë¡£
2851
2852     @latexonly \IPAlabel{mdraw_text_items} @endlatexonly  */
2853
2854 /***
2855     @seealso
2856     MTextItem, mdraw_text ().  */
2857
2858 void
2859 mdraw_text_items (MFrame *frame, MDrawWindow win, int x, int y,
2860                   MDrawTextItem *items, int nitems)
2861 {
2862   if (! (frame->device_type & MDEVICE_SUPPORT_OUTPUT))
2863     return;
2864   while (nitems-- > 0)
2865     {
2866       if (items->face)
2867         mtext_push_prop (items->mt, 0, mtext_nchars (items->mt), Mface,
2868                          items->face);
2869       mdraw_text_with_control (frame, win, x, y,
2870                                items->mt, 0, mtext_nchars (items->mt),
2871                                items->control);
2872       x += mdraw_text_extents (frame, items->mt, 0, mtext_nchars (items->mt),
2873                                items->control, NULL, NULL, NULL);
2874       x += items->delta;
2875       if (items->face)
2876         mtext_pop_prop (items->mt, 0, mtext_nchars (items->mt), Mface);
2877     }
2878 }
2879
2880 /*=*/
2881 /***en 
2882       @brief   calculate a line breaking position.
2883
2884       The function mdraw_default_line_break () calculates a line
2885       breaking position based on the line number $LINE and the
2886       coordinate $Y, when a line is too long to fit within the width
2887       limit.  $POS is the position of the character next to the last
2888       one that fits within the limit.  $FROM is the position of the
2889       first character of the line, and TO is the position of the last
2890       character displayed on the line if there were not width limit.
2891       LINE and Y are reset to 0 when a line is broken by a newline
2892       character, and incremented each time when a long line is broken
2893       because of the width limit.  
2894
2895       @return 
2896       This function returns a character position to break the
2897       line.
2898
2899 */
2900 /***ja 
2901       @brief ²þ¹Ô°ÌÃÖ¤ò·×»»¤¹¤ë.
2902
2903       ´Ø¿ô mdraw_default_line_break () ¤Ï¡¢¹Ô¤¬ºÇÂçÉýÃæ¤Ë¼ý¤Þ¤é¤Ê¤¤¾ì
2904       ¹ç¤Ë¹Ô¤ò²þ¤á¤ë°ÌÃÖ¤ò¡¢¹ÔÈÖ¹æ LINE ¤ÈºÂɸ Y ¤Ë´ð¤Å¤¤¤Æ·×»»¤¹¤ë¡£
2905       $POS ¤ÏºÇÂçÉý¤Ë¼ý¤Þ¤ëºÇ¸å¤Îʸ»ú¤Î¼¡¤Îʸ»ú¤Î°ÌÃ֤Ǥ¢¤ë¡£$FROM ¤Ï
2906       ¹Ô¤ÎºÇ½é¤Îʸ»ú¤Î°ÌÃÖ¡¢$TO ¤ÏºÇÂçÉý¤¬»ØÄꤵ¤ì¤Æ¤¤¤Ê¤±¤ì¤Ð¤½¤Î¹Ô¤Ë
2907       É½¼¨¤µ¤ì¤ëºÇ¸å¤Îʸ»ú¤Î°ÌÃ֤Ǥ¢¤ë¡£ LINE ¤È Y ¤Ï²þ¹Ôʸ»ú¤Ë¤è¤Ã¤Æ
2908       ¹Ô¤¬²þ¤Þ¤Ã¤¿ºÝ¤Ë¤Ï 0 ¤Ë¥ê¥»¥Ã¥È¤µ¤ì¡¢ºÇÂçÉý¤Ë¤è¤Ã¤Æ¹Ô¤¬²þ¤Þ¤Ã¤¿
2909       ¾ì¹ç¤Ë¤Ï 1 ¤Å¤ÄÁý¤ä¤µ¤ì¤ë¡£
2910
2911       @return 
2912       ¤³¤Î´Ø¿ô¤Ï¹Ô¤ò²þ¤á¤ëʸ»ú°ÌÃÖ¤òÊÖ¤¹¡£
2913 */
2914
2915 int
2916 mdraw_default_line_break (MText *mt, int pos,
2917                           int from, int to, int line, int y)
2918 {
2919   int c = mtext_ref_char (mt, pos);
2920   int orig_pos = pos;
2921
2922   if (c == ' ' || c == '\t')
2923     {
2924       pos++;
2925       while (pos < to
2926              && ((c = mtext_ref_char (mt, pos)) == ' ' || c == '\t'))
2927         pos++;
2928     }
2929   else
2930     {
2931       while (pos > from)
2932         {
2933           if (c == ' ' || c == '\t')
2934             break;
2935           pos--;
2936           c = mtext_ref_char (mt, pos);
2937         }
2938       if (pos == from)
2939         pos = orig_pos;
2940       else
2941         pos++;
2942     }
2943   return pos;
2944 }
2945
2946 /*=*/
2947
2948 /***en
2949     @brief Obtain per character dimension information.
2950
2951     The mdraw_per_char_extents () function computes the text dimension
2952     of each character in M-text $MT.  The faces given as text
2953     properties in $MT and the default face of frame $FRAME determine
2954     the fonts to draw the text.  Each successive element in
2955     $ARRAY_RETURN is set to the drawn metrics of successive
2956     characters, which is relative to the origin of the drawing, and a
2957     rectangle for each character in $MT.  The number of elements of
2958     $ARRAY_RETURN must be equal to or greater than the number of
2959     characters in $MT.
2960
2961     If pointer $OVERALL_RETURN is not @c NULL, this function also
2962     computes the extents of the overall text and stores the results in
2963     the members of the structure pointed to by $OVERALL_RETURN.  */
2964
2965 /***ja
2966     @brief M-text ¤Îʸ»úËè¤Îɽ¼¨ÈϰϾðÊó¤òÆÀ¤ë.
2967
2968     ´Ø¿ô mdraw_per_char_extents () ¤Ï¡¢M-text $MT Ãæ¤Î³Æʸ»ú¤Îɽ¼¨ÈÏ°Ï
2969     ¤ò·×»»¤¹¤ë¡£¤³¤Î·×»»¤ËÍѤ¤¤ë¥Õ¥©¥ó¥È¤Ï¡¢$MT ¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ç
2970     »ØÄꤵ¤ì¤¿¥Õ¥§¡¼¥¹¤Èa¡¢¥Õ¥ì¡¼¥à $FRAME ¤Î¥Ç¥Õ¥©¥ë¥È¥Õ¥§¡¼¥¹¤Ë¤è¤Ã¤Æ
2971     ·è¤Þ¤ë¡£$ARRAY_RETURN ¤Î³ÆÍ×ÁǤϡ¢Åö³º M-text Ãæ¤Î³Æʸ»ú¤Îɽ¼¨ÈÏ°Ï
2972     ¾ðÊó¤Ë¤è¤Ã¤Æ½ç¤ËËä¤á¤é¤ì¤ë¡£¤³¤Îɽ¼¨ÈϰϾðÊó¤Ï¡¢M-text ¤Îɽ¼¨¸¶ÅÀ¤«
2973     ¤é¤ÎÁêÂаÌÃ֤Ǥ¢¤ë¡£$ARRAY_RETURN ¤ÎÍ×ÁÇ¿ô¤Ï¡¢M-text ¤Î°Ê¾å¤Ç¤Ê¤±¤ì
2974     ¤Ð¤Ê¤é¤Ê¤¤¡£
2975
2976     ¥Ý¥¤¥ó¥¿ $OVERALL_RETURN ¤¬ @c NULL ¤Ç¤Ê¤¤¾ì¹ç¤Ï¡¢¥Æ¥­¥¹¥ÈÁ´ÂΤÎɽ
2977     ¼¨ÈϰϾðÊó¤â·×»»¤·¡¢¤½¤Î·ë²Ì¤ò $OVERALL_RETURN ¤Î»Ø¤¹¹½Â¤ÂΤ˳ÊǼ
2978     ¤¹¤ë¡£
2979
2980     @latexonly \IPAlabel{mdraw_per_char_extents} @endlatexonly  */
2981
2982 void
2983 mdraw_per_char_extents (MFrame *frame, MText *mt,
2984                         MDrawMetric *array_return,
2985                         MDrawMetric *overall_return)
2986 {
2987   int n = mtext_nchars (mt);
2988
2989   mdraw_text_per_char_extents (frame, mt, 0, n, NULL, array_return, NULL,
2990                                n, &n, overall_return, NULL);
2991 }
2992
2993 /***en 
2994     @brief clear cached information.    
2995
2996     The mdraw_clear_cache () function clear cached information
2997     on M-text $MT that was attached by any of the drawing functions.
2998     When the behaviour of `format' or `line_break'
2999     member functions of MDrawControl is changed, the cache must be cleared.
3000
3001     @seealso
3002     MDrawControl */
3003 /***ja 
3004     @brief ¥­¥ã¥Ã¥·¥å¾ðÊó¤ò¾Ã¤¹.
3005
3006     ´Ø¿ô mdraw_clear_cache () ¤ÏÉÁ²è´Ø¿ô¤Ë¤è¤Ã¤Æ M-text $MT ¤ËÉÕ²Ã
3007     ¤µ¤ì¤¿¥­¥ã¥Ã¥·¥å¾ðÊó¤ò¤¹¤Ù¤Æ¾Ãµî¤¹¤ë¡£MDrawControl ¤Î `format' ¤¢
3008     ¤ë¤¤¤Ï `line_break' ¥á¥ó¥Ð´Ø¿ô¤Î¿¶Éñ¤¤¤¬ÊѤï¤Ã¤¿¾ì¹ç¤Ë¤Ï¥­¥ã¥Ã¥·¥å
3009     ¤ò¾Ãµî¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
3010     @seealso
3011     MDrawControl */
3012
3013 void
3014 mdraw_clear_cache (MText *mt)
3015 {
3016   mtext_pop_prop (mt, 0, mtext_nchars (mt), M_glyph_string);
3017 }
3018
3019 /*** @} */
3020
3021 /*
3022   Local Variables:
3023   coding: euc-japan
3024   End:
3025 */