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