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