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