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