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