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