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