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