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