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