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