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