*** empty log message ***
[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., 51 Franklin Street, Fifth Floor,
21    02111-1307, USA.  */
22
23 /***en
24     @addtogroup m17nDraw
25     @brief Drawing M-texts on a window.
26
27     The m17n GUI API provides functions to draw M-texts.
28
29     The fonts used for drawing are selected automatically based on the
30     fontset and the properties of a face.  A face also specifies the
31     appearance of M-texts, i.e. font size, color, underline, etc.
32
33     The drawing format of M-texts can be controlled in a variety of
34     ways, which provides powerful 2-dimensional layout
35     facility.  */
36
37 /***ja
38     @addtogroup m17nDraw
39     @brief M-text ¤ò¥¦¥£¥ó¥É¥¦¤ËÉÁ²è¤¹¤ë.
40
41     m17n-gui API ¤Ë¤Ï¡¢M-text ¤òɽ¼¨¤¹¤ë¤¿¤á¤Î´Ø¿ô¤¬ÍÑ°Õ¤µ¤ì¤Æ¤¤¤ë¡£
42
43     É½¼¨¤ËÍѤ¤¤é¤ì¤ë¥Õ¥©¥ó¥È¤Ï¡¢¥Õ¥©¥ó¥È¥»¥Ã¥È¤È face 
44     ¤Î¥×¥í¥Ñ¥Æ¥£¤Ë´ð¤Å¤¤¤Æ¼«Æ°Åª¤Ë·èÄꤵ¤ì¤ë¡£¤Þ¤¿¡¢¥Õ¥©¥ó¥È¤Î¥µ¥¤¥º¤ä¿§¤ä²¼Àþ¤Ê¤É¤Î¸«±É¤¨¤â
45     face ¤Ë¤è¤Ã¤Æ·è¤Þ¤ë¡£
46
47     M-text ¤ÎÉÁ²è¥Õ¥©¡¼¥Þ¥Ã¥È¤Ï¿ÍͤÊÊýË¡¤ÇÀ©¸æ¤Ç¤­¤ë¤Î¤Ç¡¢¶¯ÎϤÊÆ󼡸µ¥ì¥¤¥¢¥¦¥Èµ¡Ç½¤¬¼Â¸½¤Ç¤­¤ë¡£
48     */
49
50 /*=*/
51
52 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
53 /*** @addtogroup m17nInternal
54      @{ */
55
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #include <ctype.h>
60 #include <sys/types.h>
61
62 #include "config.h"
63 #include "m17n-gui.h"
64 #include "m17n-misc.h"
65 #include "internal.h"
66 #include "symbol.h"
67 #include "mtext.h"
68 #include "textprop.h"
69 #include "internal-gui.h"
70 #include "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 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   *to_x = x;
1116   while (g->type != GLYPH_ANCHOR)
1117     {
1118       if (g->pos >= from && g->pos < to)
1119         {
1120           MGlyph *fromg = g, *cursor = NULL;
1121           MRealizedFace *rface = g->rface;
1122           int width = 0;
1123           int cursor_width = 0;
1124           int cursor_x;
1125
1126           if (! *from_idx)
1127             *from_idx = GLYPH_INDEX (g);
1128           while (g->pos >= from && g->pos < to
1129                  && g->rface == rface)
1130             {
1131               g->enabled = 1;
1132               if (g->type != GLYPH_BOX
1133                   && g->pos <= cursor_pos && g->to > cursor_pos)
1134                 {
1135                   if (! cursor)
1136                     cursor = g, cursor_x = x + width;
1137                   cursor_width += g->width;
1138                 }
1139               width += g++->width;
1140             }
1141           if (width > 0
1142               && (control->as_image
1143                   || rface->face.property[MFACE_VIDEOMODE] == Mreverse))
1144             {
1145               int this_x = x, this_width = width;
1146
1147               if (fromg->type == GLYPH_BOX)
1148                 this_x += fromg->width, this_width -= fromg->width;
1149               if (g[-1].type == GLYPH_BOX)
1150                 this_width -= g[-1].width;
1151               (frame->driver->fill_space)
1152                 (frame, win, rface, 0,
1153                  this_x, y - gstring->text_ascent, this_width,
1154                  gstring->text_ascent + gstring->text_descent,
1155                  control->clip_region);
1156             }
1157           if (cursor)
1158             {
1159               MDrawMetric rect;
1160             
1161               rect.x = cursor_x;
1162               rect.y = y - gstring->text_ascent;
1163               rect.height = gstring->text_ascent + gstring->text_descent;
1164               if (! cursor_bidi)
1165                 {
1166                   rect.width = ((control->cursor_width > 0
1167                                  && control->cursor_width < cursor_width)
1168                                 ? control->cursor_width : cursor_width);
1169                 }
1170               else
1171                 rect.width = 1;
1172               if (cursor->bidi_level % 2)
1173                 rect.x += cursor_width - rect.width;
1174               (*frame->driver->fill_space)
1175                 (frame, win, rface, 1, rect.x, rect.y, rect.width, rect.height,
1176                  control->clip_region);
1177               if (! region)
1178                 region = (*frame->driver->region_from_rect) (&rect);
1179               else
1180                 (*frame->driver->region_add_rect) (region, &rect);
1181               if (cursor_bidi)
1182                 {
1183                   if (cursor->bidi_level % 2)
1184                     rect.x -= 3;
1185                   rect.height = 2;
1186                   rect.width = cursor_width < 4 ? cursor_width : 4;
1187                   (*frame->driver->fill_space)
1188                     (frame, win, rface, 1,
1189                      rect.x, rect.y, rect.width, rect.height,
1190                      control->clip_region);
1191                   (*frame->driver->region_add_rect) (region, &rect);
1192                 }
1193             }
1194
1195           if (prev_pos >= 0)
1196             {
1197               int temp_width = 0;
1198
1199               cursor_width = 0;
1200               cursor = NULL;
1201               while (fromg < g)
1202                 {
1203                   if (fromg->type != GLYPH_BOX
1204                       && fromg->pos <= prev_pos && fromg->to > prev_pos)
1205                     {
1206                       if (! cursor)
1207                         cursor = fromg, cursor_x = x + temp_width;
1208                       cursor_width += fromg->width;
1209                     }
1210                   temp_width += fromg++->width;
1211                 }
1212               if (cursor)
1213                 {
1214                   MDrawMetric rect;
1215
1216                   rect.x = cursor_x;
1217                   if (! (cursor->bidi_level % 2))
1218                     rect.x += cursor_width - 1;
1219                   rect.y = y - gstring->text_ascent;
1220                   rect.height = gstring->text_ascent + gstring->text_descent;
1221                   rect.width = 1;
1222                   (*frame->driver->fill_space)
1223                     (frame, win, rface, 1,
1224                      rect.x, rect.y, rect.width, rect.height,
1225                      control->clip_region);
1226                   if (! region)
1227                     region = (*frame->driver->region_from_rect) (&rect);
1228                   else
1229                     (*frame->driver->region_add_rect) (region, &rect);
1230                   rect.y += rect.height - 2;
1231                   rect.height = 2;
1232                   rect.width = cursor_width < 4 ? cursor_width : 4;
1233                   if (! (cursor->bidi_level % 2))
1234                     rect.x -= rect.width - 1;
1235                   (*frame->driver->fill_space) (frame, win, rface, 1,
1236                                     rect.x, rect.y, rect.width, rect.height,
1237                                     control->clip_region);
1238                   (*frame->driver->region_add_rect) (region, &rect);
1239                 }
1240             }
1241           x += width;
1242           *to_idx = GLYPH_INDEX (g);
1243           *to_x = x;
1244         }
1245       else
1246         g++->enabled = 0;
1247     }
1248   return region;
1249 }
1250
1251 static void
1252 render_glyphs (MFrame *frame, MDrawWindow win, int x, int y, int width,
1253                MGlyphString *gstring, int from_idx, int to_idx,
1254                int reverse, MDrawRegion region)
1255 {
1256   MGlyph *g = MGLYPH (from_idx), *gend = MGLYPH (to_idx);
1257
1258   if (region)
1259     {
1260       MDrawMetric rect;
1261
1262       (*frame->driver->region_to_rect) (region, &rect);
1263       if (rect.x > x)
1264         {
1265           while (g != gend && x + g->rbearing <= rect.x)
1266             {
1267               x += g->width;
1268               width -= g++->width;
1269               while (! g->enabled && g != gend)
1270                 g++;
1271             }
1272         }
1273       rect.x += rect.width;
1274       if (rect.x < x + width)
1275         {
1276           while (g != gend
1277                  && (x + width - gend[-1].width + gend[-1].lbearing >= rect.x))
1278             {
1279               width -= (--gend)->width;
1280               while (! gend->enabled && g != gend)
1281                 gend--;
1282             }
1283           if (g != gend)
1284             while (gend->type != GLYPH_ANCHOR && gend[-1].to == gend->to)
1285               gend++;
1286         }
1287     }
1288
1289   while (g != gend)
1290     {
1291       if (g->enabled)
1292         {
1293           MRealizedFace *rface = g->rface;
1294           int width = g->width;
1295           MGlyph *from_g = g++;
1296
1297           /* Handle the glyphs of the same type/face at once.  */
1298           while (g != gend
1299                  && g->type == from_g->type
1300                  && g->rface == rface
1301                  && ((g->code == MCHAR_INVALID_CODE)
1302                      == (from_g->code == MCHAR_INVALID_CODE))
1303                  && g->enabled)
1304             width += g++->width;
1305
1306           if (from_g->type == GLYPH_CHAR)
1307             {
1308               if (rface->rfont && from_g->code != MCHAR_INVALID_CODE)
1309                 (rface->rfont->driver->render) (win, x, y, gstring, from_g, g,
1310                                                 reverse, region);
1311               else
1312                 (*frame->driver->draw_empty_boxes) (win, x, y, gstring, from_g, g,
1313                                         reverse, region);
1314             }
1315           else if (from_g->type == GLYPH_BOX)
1316             {
1317               /* Draw the left or right side of a box.  If
1318                  from_g->lbearing is nonzero, this is the left side,
1319                  else this is the right side.  */
1320               (*frame->driver->draw_box) (frame, win, gstring, from_g, x, y, 0, region);
1321             }
1322
1323           if (from_g->type != GLYPH_BOX)
1324             {
1325               if (rface->hline)
1326                 (*frame->driver->draw_hline) (frame, win, gstring, rface, reverse,
1327                                   x, y, width, region);
1328               if (rface->box
1329                   && ! reverse)
1330                 /* Draw the top and bottom side of a box.  */
1331                 (*frame->driver->draw_box) (frame, win, gstring, from_g,
1332                                    x, y, width, region);
1333             }
1334           x += width;
1335         }
1336       else
1337         g++;
1338     }
1339 }
1340
1341
1342 static int
1343 find_overlapping_glyphs (MGlyphString *gstring, int *left, int *right,
1344                          int *from_x, int *to_x)
1345 {
1346   MGlyph *g;
1347   int left_idx = *left, right_idx = *right;
1348   int left_x, right_x, x;
1349
1350   for (g = MGLYPH (*left) - 1, x = 0; g->type != GLYPH_ANCHOR; g--)
1351     {
1352       x -= g->width;
1353       if (x + g->rbearing > 0)
1354         {
1355           while (g[-1].pos == g->pos && g[-1].type != GLYPH_ANCHOR)
1356             x -= (--g)->width;
1357           left_idx = GLYPH_INDEX (g);
1358           left_x = x;
1359         }
1360     }
1361
1362   for (g = MGLYPH (*right), x = 0; g->type != GLYPH_ANCHOR; g++)
1363     {
1364       x += g->width;
1365       if (x - g->width + g->lbearing < 0)
1366         {
1367           while (g->pos == g[1].pos && g[1].type != GLYPH_ANCHOR)
1368             x += (++g)->width;
1369           right_idx = GLYPH_INDEX (g) + 1;
1370           right_x = x;
1371         }
1372     }
1373
1374   if (*left == left_idx && *right == right_idx)
1375     return 0;
1376
1377   if (*left != left_idx)
1378     {
1379       for (g = MGLYPH (*left) - 1; GLYPH_INDEX (g) >= left_idx; g--)
1380         g->enabled = 1;
1381       *left = left_idx;
1382       *from_x += left_x;
1383     }
1384   if (*right != right_idx)
1385     {
1386       for (g = MGLYPH (*right); GLYPH_INDEX (g) < right_idx; g++)
1387         g->enabled = 1;
1388       *right = right_idx;
1389       *to_x += right_x;
1390     }
1391   return 1;
1392 }
1393
1394
1395 static int
1396 gstring_width (MGlyphString *gstring, int from, int to,
1397                int *lbearing, int *rbearing)
1398 {
1399   MGlyph *g;
1400   int width;
1401
1402   if (from <= gstring->from && to >= gstring->to)
1403     {
1404       if (lbearing)
1405         *lbearing = gstring->lbearing;
1406       if (rbearing)
1407         *rbearing = gstring->rbearing;
1408       return gstring->width;
1409     }
1410
1411   if (lbearing)
1412     *lbearing = 0;
1413   if (rbearing)
1414     *rbearing = 0;
1415   for (g = MGLYPH (1), width = 0; g->type != GLYPH_ANCHOR; g++)
1416     if (g->pos >= from && g->pos < to)
1417       {
1418         if (lbearing && width + g->lbearing < *lbearing)
1419           *lbearing = width + g->lbearing;
1420         if (rbearing && width + g->rbearing > *rbearing)
1421           *rbearing = width + g->rbearing;
1422         width += g->width;
1423       }
1424   return width;
1425 }
1426
1427
1428 static void
1429 render_glyph_string (MFrame *frame, MDrawWindow win, int x, int y,
1430                      MGlyphString *gstring, int from, int to)
1431 {
1432   MDrawControl *control = &gstring->control;
1433   MDrawMetric rect;
1434   MDrawRegion clip_region, cursor_region;
1435   int from_idx, to_idx;
1436   int to_x;
1437
1438   if (from == to)
1439     return;
1440   if (control->orientation_reversed)
1441     x -= gstring->indent + gstring_width (gstring, from, to, NULL, NULL);
1442   else
1443     x += gstring->indent;
1444
1445   /* At first, draw all glyphs without cursor.  */
1446   cursor_region = draw_background (frame, win, x, y, gstring, from, to,
1447                                    &from_idx, &to_idx, &to_x);
1448
1449   if (control->partial_update)
1450     {
1451       rect.x = x;
1452       rect.width = to_x - x;
1453       if (find_overlapping_glyphs (gstring, &from_idx, &to_idx, &x, &to_x))
1454         {
1455           rect.y = y - gstring->line_ascent;
1456           rect.height = gstring->height;
1457           clip_region = (*frame->driver->region_from_rect) (&rect);
1458           if (control->clip_region)
1459             (*frame->driver->intersect_region) (clip_region, control->clip_region);
1460         }
1461       else
1462         clip_region = control->clip_region;
1463     }
1464   else
1465     clip_region = control->clip_region;
1466
1467   render_glyphs (frame, win, x, y, to_x - x, gstring, from_idx, to_idx,
1468                  0, clip_region);
1469   if (cursor_region)
1470     {
1471       if (clip_region)
1472         (*frame->driver->intersect_region) (cursor_region, clip_region);
1473       render_glyphs (frame, win, x, y, to_x - x, gstring, from_idx, to_idx,
1474                      1, cursor_region);
1475     }
1476   if (clip_region != control->clip_region)
1477     (*frame->driver->free_region) (clip_region);
1478   if (cursor_region)
1479     (*frame->driver->free_region) (cursor_region);
1480   return;
1481 }
1482
1483 static int gstring_num;
1484
1485 static void
1486 free_gstring (void *object)
1487 {
1488   MGlyphString *gstring = (MGlyphString *) object;
1489
1490   if (gstring->next)
1491     free_gstring (gstring->next);
1492   if (gstring->size > 0)
1493     free (gstring->glyphs);
1494   free (gstring);
1495   gstring_num--;
1496 }
1497
1498
1499 static MGlyphString scratch_gstring;
1500
1501 static MGlyphString *
1502 alloc_gstring (MFrame *frame, MText *mt, int pos, MDrawControl *control,
1503                int line, int y)
1504 {
1505   MGlyphString *gstring;
1506
1507   if (pos == mt->nchars)
1508     {
1509       MGlyph *g;
1510
1511       gstring = &scratch_gstring;
1512       if (gstring->size == 0)
1513         {
1514           MGlyph g_tmp;
1515
1516           INIT_GLYPH (g_tmp);
1517           g_tmp.type = GLYPH_ANCHOR;
1518           APPEND_GLYPH (gstring, g_tmp);
1519           APPEND_GLYPH (gstring, g_tmp);
1520           APPEND_GLYPH (gstring, g_tmp);
1521           gstring->glyphs[1].type = GLYPH_SPACE;
1522           gstring->glyphs[1].c = '\n';
1523           gstring->glyphs[1].code = '\n';
1524         }
1525       gstring->from = pos;
1526       g = MGLYPH (0);
1527       g->rface = frame->rface;
1528       g->pos = g->to = pos;
1529       g++;
1530       g->rface = frame->rface;
1531       g->pos = pos++, g->to = pos;
1532       g++;
1533       g->rface = frame->rface;
1534       g->pos = g->to = pos;
1535       gstring->to = pos;
1536     }
1537   else
1538     {
1539       M17N_OBJECT (gstring, free_gstring, MERROR_DRAW);
1540       MLIST_INIT1 (gstring, glyphs, 128);
1541       gstring_num++;
1542     }
1543
1544   gstring->frame = frame;
1545   gstring->tick = frame->tick;
1546   gstring->top = gstring;
1547   gstring->control = *control;
1548   gstring->indent = gstring->width_limit = 0;
1549   if (control->format)
1550     (*control->format) (line, y, &(gstring->indent), &(gstring->width_limit));
1551   else
1552     gstring->width_limit = control->max_line_width;
1553   gstring->anti_alias = control->anti_alias;
1554   return gstring;
1555 }
1556
1557 static MGlyph *find_glyph_in_gstring (MGlyphString *gstring, int pos,
1558                                       int forwardp);
1559
1560 /* Truncate the line width of GSTRING to GSTRING->width_limit.  */
1561
1562 static void
1563 truncate_gstring (MFrame *frame, MText *mt, MGlyphString *gstring)
1564 {
1565   int width;
1566   int i;
1567   int *pos_width;
1568   MGlyph *g;
1569   int pos;
1570
1571   /* Setup the array POS_WIDTH so that POS_WIDTH[I - GSTRING->from] is
1572      a width of glyphs for the character at I of MT.  If I is not a
1573      beginning of a grapheme cluster, the corresponding element is
1574      0.  */
1575   MTABLE_ALLOCA (pos_width, gstring->to - gstring->from, MERROR_DRAW);
1576   memset (pos_width, 0, sizeof (int) * (gstring->to - gstring->from));
1577   for (g = MGLYPH (1); g->type != GLYPH_ANCHOR; g++)
1578     pos_width[g->pos - gstring->from] += g->width;
1579   for (i = 0, width = 0; i < gstring->to - gstring->from; i++)
1580     {
1581       if (pos_width[i] > 0)
1582         {
1583           if (width + pos_width[i] > gstring->width_limit)
1584             break;
1585         }
1586       width += pos_width[i];
1587     }
1588
1589   pos = gstring->from + i;
1590   if (gstring->control.line_break)
1591     {
1592       pos = (*gstring->control.line_break) (mt, gstring->from + i,
1593                                             gstring->from, gstring->from + i,
1594                                             0, 0);
1595       if (pos <= gstring->from)
1596         {
1597           g = find_glyph_in_gstring (gstring, gstring->from, 1);
1598           pos = g->to;
1599         }
1600       else if (pos >= gstring->to)
1601         pos = gstring->to;
1602     }
1603   else if (i == 0)
1604     {
1605       g = find_glyph_in_gstring (gstring, gstring->from, 1);
1606       pos = g->to;
1607     }
1608   if (pos < gstring->to)
1609     {
1610       compose_glyph_string (frame, mt, gstring->from, pos, gstring);
1611       layout_glyph_string (frame, gstring);
1612     }
1613 }
1614
1615
1616 /* Return a gstring that covers a character at POS.  */
1617
1618 static MGlyphString *
1619 get_gstring (MFrame *frame, MText *mt, int pos, int to, MDrawControl *control)
1620 {
1621   MGlyphString *gstring = NULL;
1622
1623   if (pos < mtext_nchars (mt))
1624     {
1625       MTextProperty *prop = mtext_get_property (mt, pos, M_glyph_string);
1626
1627       if (prop
1628           && ((prop->start != 0
1629                && mtext_ref_char (mt, prop->start - 1) != '\n')
1630               || (prop->end < mtext_nchars (mt)
1631                   && mtext_ref_char (mt, prop->end - 1) != '\n')))
1632         {
1633           mtext_detach_property (prop);
1634           prop = NULL;
1635         }
1636       if (prop)
1637         {
1638           gstring = prop->val;
1639           if (gstring->frame != frame
1640               || gstring->tick != frame->tick
1641               || memcmp (control, &gstring->control,
1642                          (char *) (&control->with_cursor)
1643                          - (char *) (control))
1644               || control->cursor_width != gstring->control.cursor_width
1645               || control->cursor_bidi != gstring->control.cursor_bidi)
1646             {
1647               mtext_detach_property (prop);
1648               gstring = NULL;
1649             }
1650         }
1651     }
1652   else if (! control->cursor_width)
1653     return NULL;
1654
1655   if (gstring)
1656     {
1657       MGlyphString *gst;
1658       int offset;
1659
1660       offset = mtext_character (mt, pos, 0, '\n');
1661       if (offset < 0)
1662         offset = 0;
1663       else
1664         offset++;
1665       offset -= gstring->from;
1666       if (offset)
1667         for (gst = gstring; gst; gst = gst->next)
1668           {
1669             int i;
1670
1671             gst->from += offset;
1672             gst->to += offset;
1673             for (i = 0; i < gst->used; i++)
1674               {
1675                 gst->glyphs[i].pos += offset;
1676                 gst->glyphs[i].to += offset;
1677               }
1678           }
1679       M17N_OBJECT_REF (gstring);
1680     }
1681   else
1682     {
1683       int beg, end;
1684       int line = 0, y = 0;
1685
1686       if (pos < mtext_nchars (mt))
1687         {
1688           beg = mtext_character (mt, pos, 0, '\n');
1689           if (beg < 0)
1690             beg = 0;
1691           else
1692             beg++;
1693         }
1694       else
1695         beg = pos;
1696       end = mtext_nchars (mt) + (control->cursor_width != 0);
1697       gstring = alloc_gstring (frame, mt, beg, control, line, y);
1698       if (beg < mtext_nchars (mt))
1699         compose_glyph_string (frame, mt, beg, end, gstring);
1700       layout_glyph_string (frame, gstring);
1701       end = gstring->to;
1702       if (gstring->width_limit
1703           && gstring->width > gstring->width_limit)
1704         {
1705           MGlyphString *gst = gstring;
1706
1707           truncate_gstring (frame, mt, gst);
1708           while (gst->to < end)
1709             {
1710               line++, y += gst->height;
1711               gst->next = alloc_gstring (frame, mt, gst->from, control,
1712                                          line, y);
1713               gst->next->top = gstring;
1714               compose_glyph_string (frame, mt, gst->to, end, gst->next);
1715               gst = gst->next;
1716               layout_glyph_string (frame, gst);
1717               if (gst->width <= gst->width_limit)
1718                 break;
1719               truncate_gstring (frame, mt, gst);
1720             }
1721         }
1722
1723       if (! control->disable_caching && pos < mtext_nchars (mt))
1724         {
1725           MTextProperty *prop = mtext_property (M_glyph_string, gstring,
1726                                                 MTEXTPROP_VOLATILE_STRONG);
1727
1728           if (end > mtext_nchars (mt))
1729             end = mtext_nchars (mt);
1730           mtext_attach_property (mt, beg, end, prop);
1731           M17N_OBJECT_UNREF (prop);
1732         }
1733     }
1734
1735   while (gstring->to <= pos)
1736     {
1737       if (! gstring->next)
1738         mdebug_hook ();
1739       gstring = gstring->next;
1740     }
1741   gstring->control = *control;
1742
1743   return gstring;
1744 }
1745
1746
1747 static MDrawControl control_noop;
1748
1749 #define ASSURE_CONTROL(control) \
1750   if (! control)                \
1751     control = &control_noop;    \
1752   else
1753
1754
1755 static int
1756 draw_text (MFrame *frame, MDrawWindow win, int x, int y,
1757            MText *mt, int from, int to,
1758            MDrawControl *control)
1759 {
1760   MGlyphString *gstring;
1761
1762   M_CHECK_POS_X (mt, from, -1);
1763   ASSURE_CONTROL (control);
1764   if (to > mtext_nchars (mt) + (control->cursor_width != 0))
1765     to = mtext_nchars (mt) + (control->cursor_width != 0);
1766   else if (to < from)
1767     to = from;
1768
1769   gstring = get_gstring (frame, mt, from, to, control);
1770   if (! gstring)
1771     MERROR (MERROR_DRAW, -1);
1772   render_glyph_string (frame, win, x, y, gstring, from, to);
1773   from = gstring->to;
1774   while (from < to)
1775     {
1776       y += gstring->line_descent;
1777       M17N_OBJECT_UNREF (gstring->top);
1778       gstring = get_gstring (frame, mt, from, to, control);
1779       y += gstring->line_ascent;
1780       render_glyph_string (frame, win, x, y, gstring, from, to);
1781       from = gstring->to;
1782     }
1783   M17N_OBJECT_UNREF (gstring->top);
1784
1785   return 0;
1786 }
1787
1788
1789 static MGlyph *
1790 find_glyph_in_gstring (MGlyphString *gstring, int pos, int forwardp)
1791 {
1792   MGlyph *g;
1793
1794   if (forwardp)
1795     {
1796       for (g = MGLYPH (1); g->type != GLYPH_ANCHOR; g++)
1797         if (g->pos <= pos && g->to > pos)
1798           break;
1799     }
1800   else
1801     {
1802       for (g = MGLYPH (gstring->used - 2); g->type != GLYPH_ANCHOR; g--)
1803         if (g->pos <= pos && g->to > pos)
1804           break;
1805     }
1806   return g;
1807 }
1808
1809 \f
1810 /* for debugging... */
1811 char work[16];
1812
1813 char *
1814 dump_combining_code (int code)
1815 {
1816   char *vallign = "tcbB";
1817   char *hallign = "lcr";
1818   char *p;
1819   int off_x, off_y;
1820
1821   if (! code)
1822     return "none";
1823   if (COMBINING_BY_CLASS_P (code))
1824     code = combining_code_from_class (COMBINING_CODE_CLASS (code));
1825   work[0] = vallign[COMBINING_CODE_BASE_Y (code)];
1826   work[1] = hallign[COMBINING_CODE_BASE_X (code)];
1827   off_y = COMBINING_CODE_OFF_Y (code) - 128;
1828   off_x = COMBINING_CODE_OFF_X (code) - 128;
1829   if (off_y > 0)
1830     sprintf (work + 2, "+%d", off_y);
1831   else if (off_y < 0)
1832     sprintf (work + 2, "%d", off_y);
1833   else if (off_x == 0)
1834     sprintf (work + 2, ".");
1835   p = work + strlen (work);
1836   if (off_x > 0)
1837     sprintf (p, ">%d", off_x);
1838   else if (off_x < 0)
1839     sprintf (p, "<%d", -off_x);
1840   p += strlen (p);
1841   p[0] = vallign[COMBINING_CODE_ADD_Y (code)];
1842   p[1] = hallign[COMBINING_CODE_ADD_X (code)];
1843   p[2] = '\0';
1844   return work;
1845 }
1846
1847 void
1848 dump_gstring (MGlyphString *gstring, int indent)
1849 {
1850   char *prefix = (char *) alloca (indent + 1);
1851   MGlyph *g, *last_g = gstring->glyphs + gstring->used;
1852
1853   memset (prefix, 32, indent);
1854   prefix[indent] = 0;
1855
1856   fprintf (stderr, "(glyph-string");
1857
1858   for (g = MGLYPH (0); g < last_g; g++)
1859     fprintf (stderr,
1860              "\n%s  (%02d %s pos:%d-%d c:%04X code:%04X face:%x cmb:%s w:%02d bidi:%d)",
1861              prefix,
1862              g - gstring->glyphs,
1863              (g->type == GLYPH_SPACE ? "SPC": g->type == GLYPH_PAD ? "PAD"
1864               : g->type == GLYPH_ANCHOR ? "ANC"
1865               : g->type == GLYPH_BOX ? "BOX" : "CHR"),
1866              g->pos, g->to, g->c, g->code, (unsigned) g->rface,
1867              dump_combining_code (g->combining_code),
1868              g->width, g->bidi_level);
1869   fprintf (stderr, ")");
1870 }
1871 \f
1872
1873 /* m17n-X internal APIs */
1874
1875 int
1876 mdraw__init ()
1877 {
1878   M_glyph_string = msymbol_as_managing_key ("  glyph-string");
1879
1880   memset (&scratch_gstring, 0, sizeof (scratch_gstring));
1881   MLIST_INIT1 (&scratch_gstring, glyphs, 3);
1882
1883   Mcommon = msymbol ("common");
1884
1885   McatCc = msymbol ("Cc");
1886   McatCf = msymbol ("Cf");
1887
1888   MbidiR = msymbol ("R");
1889   MbidiAL = msymbol ("AL");
1890   MbidiRLE = msymbol ("RLE");
1891   MbidiRLO = msymbol ("RLO");
1892   MbidiBN = msymbol ("BN");
1893   MbidiS = msymbol ("S");
1894   MbidiNSM = msymbol ("NSM");
1895 #ifdef HAVE_FRIBIDI
1896   fribidi_set_mirroring (TRUE);
1897 #endif
1898
1899   M_break_at_space = msymbol ("bs");
1900   M_break_at_word = msymbol ("bw");
1901   M_break_at_any = msymbol ("ba");
1902   M_kinsoku_bol = msymbol ("kb");
1903   M_kinsoku_eol = msymbol ("ke");
1904
1905   return 0;
1906 }
1907
1908 void
1909 mdraw__fini ()
1910 {
1911   MLIST_FREE1 (&scratch_gstring, glyphs);
1912   M17N_OBJECT_UNREF (linebreak_table);
1913   linebreak_table = NULL;
1914 }
1915
1916 /*** @} */
1917 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
1918
1919 \f
1920 /* External API */
1921 /*** @addtogroup m17nDraw */
1922 /*** @{ */
1923
1924 /*=*/
1925 /***en
1926     @brief Draw an M-text on a window.
1927
1928     The mdraw_text () function draws the text between $FROM and $TO of
1929     M-text $MT on window $WIN of frame $FRAME at coordinate ($X, $Y).
1930
1931     The appearance of the text (size, style, color, etc) is specified
1932     by the value of the text property whose key is @c Mface.  If the
1933     M-text or a part of the M-text does not have such a text property,
1934     the default face of $FRAME is used.
1935
1936     The font used to draw a character in the M-text is selected from
1937     the value of the fontset property of a face by the following
1938     algorithm:
1939
1940     <ol>
1941
1942     <li> Search the text properties given to the character for the one
1943          whose key is @c Mcharset; its value should be either a symbol
1944          specifying a charset or #Mnil.  If the value is #Mnil,
1945          proceed to the next step.
1946
1947          Otherwise, search the mapping table of the fontset for the
1948          charset.  If no entry is found proceed to the next step.  
1949
1950          If an entry is found, use one of the fonts in the entry that
1951          has a glyph for the character and that matches best with the
1952          face properties.  If no such font exists, proceed to the next
1953          step.
1954
1955     <li> Get the character property "script" of the character.  If it is
1956          inherited, get the script property from the previous
1957          characters.  If there is no previous character, or none of
1958          them has the script property other than inherited, proceed to
1959          the next step.
1960
1961          Search the text properties given to the character for the one
1962          whose key is @c Mlanguage; its value should be either a
1963          symbol specifying a language or @c Mnil.
1964
1965          Search the mapping table of the fontset for the combination
1966          of the script and language.  If no entry is found, proceed to
1967          the next step.  
1968
1969          If an entry is found, use one of the fonts in the entry that
1970          has a glyph for the character and that matches best with the
1971          face properties.  If no such font exists, proceed to the next
1972          step.
1973
1974     <li> Search the fall-back table of the fontset for a font that has
1975          a glyph of the character.  If such a font is found, use that
1976          font.
1977
1978     </ol>
1979
1980     If no font is found by the algorithm above, this function draws an
1981     empty box for the character.
1982
1983     This function draws only the glyph foreground.  To specify the
1984     background color, use mdraw_image_text () or
1985     mdraw_text_with_control ().
1986
1987     This function is the counterpart of <tt>XDrawString ()</tt>,
1988     <tt>XmbDrawString ()</tt>, and <tt>XwcDrawString ()</tt> functions
1989     in the X Window System.
1990
1991     @return
1992     If the operation was successful, mdraw_text () returns 0.  If an
1993     error is detected, it returns -1 and assigns an error code to the
1994     external variable #merror_code.  */
1995 /***ja
1996     @brief ¥¦¥£¥ó¥É¥¦¤Ë M-text ¤òÉÁ²è¤¹¤ë.
1997
1998     ´Ø¿ô mdraw_text () ¤Ï¡¢¥Õ¥ì¡¼¥à $FRAME ¤Î¥¦¥£¥ó¥É¥¦ $WIN ¤ÎºÂɸ 
1999     ($X, $Y) ¤Ë¡¢M-text $MT ¤Î $FROM ¤«¤é $TO ¤Þ¤Ç¤Î¥Æ¥­¥¹¥È¤òÉÁ²è¤¹¤ë¡£
2000
2001     ¥Æ¥­¥¹¥È¤Î¸«±É¤¨¡Ê¥Õ¥©¥ó¥È¡¢¥¹¥¿¥¤¥ë¡¢¿§¤Ê¤É¡Ë¤Ï¡¢¥­¡¼¤¬ @c Mface 
2002     ¤Ç¤¢¤ë¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤ÎÃͤˤè¤Ã¤Æ·è¤Þ¤ë¡£M-text 
2003     ¤Î°ìÉô¤¢¤ë¤¤¤ÏÁ´Éô¤Ë¤½¤Î¤è¤¦¤Ê¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤¬ÉÕ¤¤¤Æ¤¤¤Ê¤¤¾ì¹ç¤Ë¤Ï¡¢$FRAME 
2004     ¤Î¥Ç¥Õ¥©¥ë¥È¥Õ¥§¡¼¥¹¤òÂå¤ï¤ê¤ËÍѤ¤¤ë¡£
2005
2006     M-text ¤Î³Æʸ»ú¤òɽ¼¨¤¹¤ë¥Õ¥©¥ó¥È¤Ï¡¢¥Õ¥§¡¼¥¹¤Î fontset 
2007     ¥×¥í¥Ñ¥Æ¥£¤ÎÃͤΤ¦¤Á¤«¤é¡¢°Ê²¼¤Î¥¢¥ë¥´¥ê¥º¥à¤ÇÁª¤Ð¤ì¤ë¡£
2008
2009     <ol>
2010
2011     <li> ¤½¤Îʸ»ú¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Î¤¦¤Á¡¢¥­¡¼¤¬ @c Mcharset
2012          ¤Ç¤¢¤ë¤â¤Î¤ÎÃͤòÄ´¤Ù¤ë¡£¤³¤ÎÃͤÏʸ»ú¥»¥Ã¥È¤òɽ¤ï¤¹¥·¥ó¥Ü¥ë¤« #Mnil 
2013          ¤Î¤É¤Á¤é¤«¤Ç¤¢¤ë¡£#Mnil ¤Ê¤é¤Ð¡¢¼¡¤Î¥¹¥Æ¥Ã¥×¤Ë¿Ê¤à¡£
2014          ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢fontset 
2015          ¤Î¥Þ¥Ã¥Ô¥ó¥°¥Æ¡¼¥Ö¥ë¤Ë¤½¤Îʸ»ú¥»¥Ã¥ÈÍѤΥե©¥ó¥È¤¬¤¢¤ë¤«¤É¤¦¤«¤òÄ´¤Ù¤ë¡£
2016          Ìµ¤±¤ì¤Ð¡¢¼¡¤Î¥¹¥Æ¥Ã¥×¤Ë¿Ê¤à¡£
2017          
2018          ¤½¤Îʸ»ú¥»¥Ã¥ÈÍѤΥե©¥ó¥È¤¬¤ß¤Ä¤«¤ì¤Ð¡¢¤½¤ì¤é¤Î¤¦¤Á¸½ºß¤Îʸ»úÍѤΥ°¥ê¥Õ¤ò»ý¤Á¡¢¥Õ¥§¡¼¥¹¤Î³Æ¥×¥í¥Ñ¥Æ¥£¤ËºÇ¤â¤è¤¯¹çÃפ¹¤ë¤â¤Î¤ò»È¤¦¡£
2019          ¤½¤Î¤è¤¦¤Ê¥Õ¥©¥ó¥È¤¬Ìµ¤±¤ì¤Ð¼¡¤Î¥¹¥Æ¥Ã¥×¤Ë¿Ê¤à¡£
2020
2021     <li> ¤½¤Îʸ»ú¤Îʸ»ú¥×¥í¥Ñ¥Æ¥£ "script" ¡Ê¥¹¥¯¥ê¥×¥È¡Ë¤òÄ´¤Ù¤ë¡£
2022          ¤½¤Î¥×¥í¥Ñ¥Æ¥£¤¬·Ñ¾µ¤µ¤ì¤Æ¤¤¤ë¤Ê¤é¤Ð¤½¤ì°ÊÁ°¤Îʸ»ú¤Îʸ»ú¥×¥í¥Ñ¥Æ¥£ "script" 
2023          ¤òÄ´¤Ù¤ë¡£Á°¤Îʸ»ú¤¬¤Ê¤«¤Ã¤¿¤ê¡¢¤½¤Îʸ»ú¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Ã¤Æ¤¤¤Ê¤«¤Ã¤¿¾ì¹ç¤Ë¤Ï¡¢¼¡¤Î¥¹¥Æ¥Ã¥×¤Ë¿Ê¤à¡£
2024
2025          ¤½¤Îʸ»ú¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Î¤¦¤Á¡¢¥­¡¼¤¬ @c Mlanguage ¤Ç¤¢¤ë¤â¤Î¤ÎÃͤòÄ´¤Ù¤ë¡£
2026          ¤³¤ÎÃͤϸÀ¸ì¤òɽ¤ï¤¹¥·¥ó¥Ü¥ë¤« @c Mnil ¤Î¤¤¤º¤ì¤«¤Ç¤¢¤ë¡£
2027
2028          ¤½¤Î¸À¸ì¤È¥¹¥¯¥ê¥×¥È¤ÎÁȤ߹ç¤ï¤»¤¬ fontset
2029          ¤Î¥Þ¥Ã¥Ô¥ó¥°¥Æ¡¼¥Ö¥ë¤Ë¤¢¤ë¤«¤É¤¦¤«¤òÄ´¤Ù¤ë¡£¸«¤Ä¤«¤é¤Ê¤±¤ì¤Ð¼¡¤Î¥¹¥Æ¥Ã¥×¤Ë¿Ê¤à¡£
2030
2031          ¸«¤Ä¤«¤Ã¤¿¤Ð¤¢¤¤¤Ë¤Ï¡¢¤½¤ì¤é¤Î¥Õ¥©¥ó¥È¤Î¤¦¤Á¸½ºß¤Îʸ»úÍѤΥ°¥ê¥Õ¤ò»ý¤Á¡¢¥Õ¥§¡¼¥¹¤Î³Æ¥×¥í¥Ñ¥Æ¥£¤ËºÇ¤â¤è¤¯¹çÃפ·¤Æ¤¤¤ë¤â¤Î¤ò»È¤¦¡£
2032          ¤½¤Î¤è¤¦¤Ê¥Õ¥©¥ó¥È¤¬Ìµ¤±¤ì¤Ð¼¡¤Î¥¹¥Æ¥Ã¥×¤Ë¿Ê¤à¡£
2033
2034     <li> ¤½¤Îʸ»ú¤Î¥°¥ê¥Õ¤ò»ý¤Ä¥Õ¥©¥ó¥È¤ò¡¢¥Õ¥©¥ó¥È¥»¥Ã¥È¤Î fall-back 
2035          ¥Æ¡¼¥Ö¥ë¤«¤éõ¤¹¡£¥Õ¥©¥ó¥È¤¬¸«¤Ä¤«¤ì¤Ð¤½¤ì¤ò»È¤¦¡£
2036
2037     </ol>
2038
2039     °Ê¾å¤Î¥¢¥ë¥´¥ê¥º¥à¤Ç¥Õ¥©¥ó¥È¤¬¸«¤Ä¤«¤é¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï¤½¤Îʸ»ú¤È¤·¤Æ¶õ¤Î»Í³Ñ·Á¤òɽ¼¨¤¹¤ë¡£
2040
2041     ¤³¤Î´Ø¿ô¤¬ÉÁ²è¤¹¤ë¤Î¤Ï¥°¥ê¥Õ¤ÎÁ°·Ê¤À¤±¤Ç¤¢¤ë¡£ÇØ·Ê¿§¤ò»ØÄꤹ¤ë¤Ë¤Ï¡¢´Ø¿ô
2042     mdraw_image_text () ¤«´Ø¿ô mdraw_text_with_control () ¤ò»È¤¦¤³¤È¡£
2043
2044     ¤³¤Î´Ø¿ô¤Ï¡¢X ¥¦¥£¥ó¥É¥¦¤Ë¤ª¤±¤ë´Ø¿ô <tt>XDrawString ()</tt>,
2045     <tt>XmbDrawString ()</tt>, <tt>XwcDrawString ()</tt> ¤ËÁêÅö¤¹¤ë¡£
2046
2047     @return
2048     ½èÍý¤¬À®¸ù¤·¤¿¾ì¹ç¡¢mdraw_text () ¤Ï 0 ÊÖ¤¹¡£¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì¤¿¾ì¹ç¤Ï
2049     -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
2050
2051     @latexonly \IPAlabel{mdraw_text} @endlatexonly  */
2052
2053 /***
2054     @errors
2055     @c MERROR_RANGE
2056
2057     @seealso
2058     mdraw_image_text ()  */
2059
2060 int
2061 mdraw_text (MFrame *frame, MDrawWindow win, int x, int y,
2062             MText *mt, int from, int to)
2063 {
2064   MDrawControl control;
2065
2066   M_CHECK_WRITABLE (frame, MERROR_DRAW, -1);
2067   memset (&control, 0, sizeof control);
2068   control.as_image = 0;
2069   return draw_text (frame, win, x, y, mt, from, to, &control);
2070 }
2071
2072 /*=*/
2073
2074
2075 /***en
2076     @brief Draw an M-text on a window as an image.
2077
2078     The mdraw_image_text () function draws the text between $FROM and
2079     $TO of M-text $MT as image on window $WIN of frame $FRAME at
2080     coordinate ($X, $Y).
2081
2082     The way to draw a text is the same as in mdraw_text () except that
2083     this function also draws the background with the color specified
2084     by faces.
2085
2086     This function is the counterpart of <tt>XDrawImageString ()</tt>,
2087     <tt>XmbDrawImageString ()</tt>, and <tt>XwcDrawImageString ()</tt>
2088     functions in the X Window System.
2089
2090     @return
2091     If the operation was successful, mdraw_image_text () returns 0.
2092     If an error is detected, it returns -1 and assigns an error code
2093     to the external variable #merror_code.  */
2094
2095 /***ja
2096     @brief ¥Ç¥£¥¹¥×¥ì¥¤¤ËM-text ¤ò²èÁü¤È¤·¤ÆÉÁ¤¯.
2097   
2098     ´Ø¿ô mdraw_image_text () ¤Ï¡¢¥Õ¥ì¡¼¥à $FRAME ¤Î¥¦¥£¥ó¥É¥¦ $WIN 
2099     ¤ÎºÂɸ ($X, $Y) ¤Ë¡¢M-text $MT ¤Î $FROM ¤«¤é $TO 
2100     ¤Þ¤Ç¤Î¥Æ¥­¥¹¥È¤ò²èÁü¤È¤·¤ÆÉÁ¤¯¡£
2101
2102     ¥Æ¥­¥¹¥È¤ÎÉÁ²èÊýË¡¤Ï mdraw_text ()
2103     ¤È¤Û¤ÜƱ¤¸¤Ç¤¢¤ë¤¬¡¢¤³¤Î´Ø¿ô¤Ç¤Ï¥Õ¥§¡¼¥¹¤Ç»ØÄꤵ¤ì¤¿¿§¤ÇÇطʤâÉÁ¤¯ÅÀ¤¬°Û¤Ê¤Ã¤Æ¤¤¤ë¡£
2104
2105     ¤³¤Î´Ø¿ô¤Ï¡¢X ¥¦¥£¥ó¥É¥¦¤Ë¤ª¤±¤ë <tt>XDrawImageString ()</tt>,
2106     <tt>XmbDrawImageString ()</tt>, <tt>XwcDrawImageString ()</tt> 
2107     ¤ËÁêÅö¤¹¤ë¡£
2108
2109     @return
2110     ½èÍý¤¬À®¸ù¤·¤¿¾ì¹ç¡¢mdraw_image_text () ¤Ï 0 
2111     ¤òÊÖ¤¹¡£¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì¤¿¾ì¹ç¤Ï -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #m_errro ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
2112
2113     @latexonly \IPAlabel{mdraw_image_text} @endlatexonly   */
2114
2115 /***
2116     @errors
2117     @c MERROR_RANGE
2118
2119     @seealso
2120     mdraw_text ()  */
2121
2122 int
2123 mdraw_image_text (MFrame *frame, MDrawWindow win, int x, int y,
2124                   MText *mt, int from, int to)
2125 {
2126   MDrawControl control;
2127
2128   M_CHECK_WRITABLE (frame, MERROR_DRAW, -1);
2129   memset (&control, 0, sizeof control);
2130   control.as_image = 1;
2131   return draw_text (frame, win, x, y, mt, from, to, &control);
2132 }
2133
2134 /*=*/
2135
2136 /***en
2137     @brief Draw an M-text on a window with fine control.
2138
2139     The mdraw_text_with_control () function draws the text between
2140     $FROM and $TO of M-text $MT on windows $WIN of frame $FRAME at
2141     coordinate ($X, $Y).
2142
2143     The way to draw a text is the same as in mdraw_text () except that
2144     this function also follows what specified in the drawing control
2145     object $CONTROL.
2146
2147     For instance, if <two_dimensional> of $CONTROL is nonzero, this
2148     function draw an M-text 2-dimensionally, i.e., newlines in M-text
2149     breaks lines and the following characters are drawn in the next
2150     line.  See the documentation of the structure @ MDrawControl for
2151     more detail.  */
2152
2153 /***ja
2154     @brief ¥Ç¥£¥¹¥×¥ì¥¤¤ËM-text ¤ò¾ÜºÙ¤ÊÀ©¸æ¤Ä¤­¤ÇÉÁ¤¯.
2155
2156     ´Ø¿ô mdraw_text_with_control () ¤Ï¡¢¥Õ¥ì¡¼¥à $FRAME ¤Î¥¦¥£¥ó¥É¥¦ 
2157     $WIN ¤ÎºÂɸ ($X, $Y) ¤Ë¡¢M-text $MT ¤Î $FROM ¤«¤é $TO ¤Þ¤Ç¤Î¥Æ¥­¥¹
2158     ¥È¤òÉÁ¤¯¡£
2159
2160     ¥Æ¥­¥¹¥È¤ÎÉÁ²èÊýË¡¤Ï mdraw_text () ¤È¤Û¤ÜƱ¤¸¤Ç¤¢¤ë¤¬¡¢¤³¤Î´Ø¿ô¤ÏÉÁ²èÀ©¸æÍѤΥª¥Ö¥¸¥§¥¯¥È
2161     $CONTROL ¤Î»Ø¼¨¤Ë¤â½¾¤¦ÅÀ¤¬°Û¤Ê¤Ã¤Æ¤¤¤ë¡£
2162
2163     ¤¿¤È¤¨¤Ð $CONTROL ¤Î <two_dimensional> ¤¬¥¼¥í¤Ç¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï 
2164     M-text ¤ò2¼¡¸µÅª¤ËÉÁ¤¯¡£¤¹¤Ê¤ï¤Á M-text Ãæ¤Î²þ¹Ô¤Ç¹Ô¤ò²þ¤á¡¢Â³¤¯Ê¸»ú¤Ï¼¡¤Î¹Ô¤ËÉÁ¤¯¡£¾ÜºÙ¤Ï¹½Â¤ÂÎ
2165     @ MDrawControl ¤ÎÀâÌÀ¤ò»²¾È¤¹¤ë¤³¤È¡£*/
2166
2167 int
2168 mdraw_text_with_control (MFrame *frame, MDrawWindow win, int x, int y,
2169                          MText *mt, int from, int to, MDrawControl *control)
2170 {
2171   M_CHECK_WRITABLE (frame, MERROR_DRAW, -1);
2172   return draw_text (frame, win, x, y, mt, from, to, control);
2173 }
2174
2175 /*=*/
2176
2177 /***en
2178     @brief Compute text pixel width.
2179
2180     The mdraw_text_extents () function computes the width of text
2181     between $FROM and $TO of M-text $MT when it is drawn on a window
2182     of frame $FRAME using the mdraw_text_with_control () function with
2183     the drawing control object $CONTROL.
2184
2185     If $OVERALL_INK_RETURN is not @c NULL, this function also computes
2186     the bounding box of character ink of the M-text, and stores the
2187     results in the members of the structure pointed to by
2188     $OVERALL_INK_RETURN.  If the M-text has a face specifying a
2189     surrounding box, the box is included in the bounding box.
2190
2191     If $OVERALL_LOGICAL_RETURN is not @c NULL, this function also
2192     computes the bounding box that provides minimum spacing to other
2193     graphical features (such as surrounding box) for the M-text, and
2194     stores the results in the members of the structure pointed to by
2195     $OVERALL_LOGICAL_RETURN.
2196
2197     If $OVERALL_LINE_RETURN is not @c NULL, this function also
2198     computes the bounding box that provides minimum spacing to the
2199     other M-text drawn, and stores the results in the members of the
2200     structure pointed to by $OVERALL_LINE_RETURN.  This is a union of
2201     $OVERALL_INK_RETURN and $OVERALL_LOGICAL_RETURN if the members
2202     min_line_ascent, min_line_descent, max_line_ascent, and
2203     max_line_descent of $CONTROL are all zero.
2204
2205     @return
2206     This function returns the width of the text to be drawn in the
2207     unit of pixels.  If $CONTROL->two_dimensional is nonzero and the
2208     text is drawn in multiple physical lines, it returns the width of
2209     the widest line.  If an error occurs, it returns -1 and assigns an
2210     error code to the external variable #merror_code.  */
2211
2212
2213 /***ja 
2214     @brief ¥Æ¥­¥¹¥È¤ÎÉý¡Ê¥Ô¥¯¥»¥ëñ°Ì¡Ë¤ò·×»»¤¹¤ë.
2215
2216     ´Ø¿ô mdraw_text_extents () ¤Ï¡¢´Ø¿ô mdraw_text_with_control () 
2217     ¤¬ÉÁ²èÀ©¸æ¥ª¥Ö¥¸¥§¥¯¥È $CONTROL ¤òÍѤ¤¤Æ M-text $MT ¤Î $FROM ¤«¤é $TO 
2218     ¤Þ¤Ç¤ò¥Õ¥ì¡¼¥à $FRAME ¤Ëɽ¼¨¤¹¤ëºÝ¤ËɬÍפȤʤëÉý¤òÊÖ¤¹¡£
2219
2220     $OVERALL_INK_RETURN ¤¬ @c NULL ¤Ç¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï M-text 
2221     ¤Îʸ»ú¤Î¥¤¥ó¥¯¤Î¥Ð¥¦¥ó¥Ç¥£¥ó¥°¥Ü¥Ã¥¯¥¹¤â·×»»¤·¡¢$OVERALL_INK_RETURN 
2222     ¤¬»Ø¤¹¹½Â¤ÂΤΥá¥ó¥Ð¤Ë¤½¤Î·ë²Ì¤òÀßÄꤹ¤ë¡£M-text ¤Ë°Ï¤ßÏÈ (surrounding box)
2223     ¤ò»ØÄꤹ¤ë¥Õ¥§¡¼¥¹¤¬¤¢¤ì¤Ð¡¢¤½¤ì¤â¥Ð¥¦¥ó¥Ç¥£¥ó¥°¥Ü¥Ã¥¯¥¹¤Ë´Þ¤à¡£
2224
2225     $OVERALL_LOGICAL_RETURN ¤¬ @c NULL ¤Ç¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï M-text 
2226     ¤È¾¤Î graphical feature ¡Ê°Ï¤ßÏȤʤɡË
2227     ¤È¤Î´Ö¤ÎºÇ¾®¤Î¥¹¥Ú¡¼¥¹¤ò¼¨¤¹¥Ð¥¦¥ó¥Ç¥£¥ó¥°¥Ü¥Ã¥¯¥¹¤â·×»»¤·¡¢$OVERALL_LOGICAL_RETURN
2228     ¤¬»Ø¤¹¹½Â¤ÂΤΥá¥ó¥Ð¤Ë¤½¤Î·ë²Ì¤òÀßÄꤹ¤ë¡£
2229
2230     $OVERALL_LINE_RETURN ¤¬ @c NULL ¤Ç¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï¾¤Î M-text 
2231     ¤È¤Î´Ö¤ÎºÇ¾®¤Î¥¹¥Ú¡¼¥¹¤ò¼¨¤¹¥Ð¥¦¥ó¥Ç¥£¥ó¥°¥Ü¥Ã¥¯¥¹¤â·×»»¤·¡¢
2232     $OVERALL_LINE_RETURN ¤¬»Ø¤¹¹½Â¤ÂΤΥá¥ó¥Ð¤Ë¤½¤Î·ë²Ì¤òÀßÄꤹ¤ë¡£¥ª¥Ö¥¸¥§¥¯¥È
2233     $CONTROL ¤Î¥á¥ó¥Ð min_line_ascent, min_line_descent,
2234     max_line_ascent, max_line_descent ¤¬¤¹¤Ù¤Æ0¤Î»þ¤Ë¤Ï¡¢¤³¤ÎÃͤϠ
2235     $OVERALL_INK_RETURN ¤È$OVERALL_LOGICAL_RETURN ¤ÎϤȤʤ롣
2236
2237     @return 
2238     ¤³¤Î´Ø¿ô¤Ïɽ¼¨¤ËɬÍפʥƥ­¥¹¥È¤ÎÉý¤ò¥Ô¥¯¥»¥ëñ°Ì¤ÇÊÖ¤¹¡£$CONTROL->two_dimensional
2239     ¤¬0¤Ç¤Ê¤¯¡¢¥Æ¥­¥¹¥È¤¬Ê£¿ô¤Î¹Ô¤ËÅϤäÆÉÁ¤«¤ì¤ë¾ì¹ç¤Ë¤Ï¡¢ºÇÂç¤ÎÉý¤òÊÖ¤¹¡£¥¨¥é¡¼¤¬À¸¤¸¤¿¾ì¹ç¤Ï
2240     -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
2241
2242     @latexonly \IPAlabel{mdraw_text_extents} @endlatexonly  */
2243
2244 /***
2245     @errors
2246     @c MERROR_RANGE  */
2247
2248 int
2249 mdraw_text_extents (MFrame *frame,
2250                     MText *mt, int from, int to, MDrawControl *control,
2251                     MDrawMetric *overall_ink_return,
2252                     MDrawMetric *overall_logical_return,
2253                     MDrawMetric *overall_line_return)
2254 {
2255   MGlyphString *gstring;
2256   int y = 0;
2257   int width, lbearing, rbearing;
2258
2259   ASSURE_CONTROL (control);
2260   M_CHECK_POS_X (mt, from, -1);
2261   if (to > mtext_nchars (mt) + (control->cursor_width != 0))
2262     to = mtext_nchars (mt) + (control->cursor_width != 0);
2263   else if (to < from)
2264     to = from;
2265
2266   gstring = get_gstring (frame, mt, from, to, control);
2267   if (! gstring)
2268     MERROR (MERROR_DRAW, -1);
2269   width = gstring_width (gstring, from, to, &lbearing, &rbearing);
2270   if (overall_ink_return)
2271     overall_ink_return->y = - gstring->physical_ascent;
2272   if (overall_logical_return)
2273     overall_logical_return->y = - gstring->ascent;
2274   if (overall_line_return)
2275     overall_line_return->y = - gstring->line_ascent;
2276
2277   for (from = gstring->to; from < to; from = gstring->to)
2278     {
2279       int this_width, this_lbearing, this_rbearing;
2280
2281       y += gstring->line_descent;
2282       M17N_OBJECT_UNREF (gstring->top);
2283       gstring = get_gstring (frame, mt, from, to, control);
2284       this_width = gstring_width (gstring, from, to,
2285                                   &this_lbearing, &this_rbearing);
2286       y += gstring->line_ascent;
2287       if (width < this_width)
2288         width = this_width;
2289       if (rbearing < this_rbearing)
2290         rbearing = this_rbearing;
2291       if (lbearing > this_lbearing)
2292         lbearing = this_lbearing;
2293     }
2294   if (overall_ink_return)
2295     {
2296       overall_ink_return->x = lbearing;
2297       overall_ink_return->width = rbearing - lbearing;
2298       overall_ink_return->height
2299         = y + gstring->physical_descent - overall_ink_return->y;
2300     }
2301   if (overall_logical_return)
2302     {
2303       overall_logical_return->x = 0;
2304       overall_logical_return->width = width;
2305       overall_logical_return->height
2306         = y + gstring->descent - overall_logical_return->y;
2307     }
2308   if (overall_line_return)
2309     {
2310       overall_line_return->x = lbearing;
2311       overall_line_return->width = MAX (width, rbearing - lbearing);
2312       overall_line_return->height
2313         = y + gstring->line_descent - overall_line_return->y;
2314     }
2315
2316   M17N_OBJECT_UNREF (gstring->top);
2317   return width;
2318 }
2319
2320 /*=*/
2321
2322 /***en
2323     @brief Compute the text dimensions of each character of M-text.
2324
2325     The mdraw_text_per_char_extents () function computes the drawn
2326     metric of each character between $FROM and $TO of M-text $MT
2327     assuming that they are drawn on a window of frame $FRAME using the
2328     mdraw_text_with_control () function with the drawing control
2329     object $CONTROL.
2330
2331     $ARRAY_SIZE specifies the size of $INK_ARRAY_RETURN and
2332     $LOGICAL_ARRAY_RETURN.  Each successive element of
2333     $INK_ARRAY_RETURN and $LOGICAL_ARRAY_RETURN are set to the drawn
2334     ink and logical metrics of successive characters respectively,
2335     relative to the drawing origin of the M-text.  The number of
2336     elements of $INK_ARRAY_RETURN and $LOGICAL_ARRAY_RETURN that have
2337     been set is returned to $NUM_CHARS_RETURN.
2338
2339     If $ARRAY_SIZE is too small to return all metrics, the function
2340     returns -1 and store the requested size in $NUM_CHARS_RETURN.
2341     Otherwise, it returns zero.
2342
2343     If pointer $OVERALL_INK_RETURN and $OVERALL_LOGICAL_RETURN are not
2344     @c NULL, this function also computes the metrics of the overall
2345     text and stores the results in the members of the structure
2346     pointed to by $OVERALL_INK_RETURN and $OVERALL_LOGICAL_RETURN.
2347
2348     If $CONTROL->two_dimensional is nonzero, this function computes
2349     only the metrics of characters in the first line.  */
2350 /***ja
2351     @brief  M-text ¤Î³Æʸ»ú¤Îɽ¼¨ÈϰϤò·×»»¤¹¤ë.
2352
2353     ´Ø¿ô mdraw_text_per_char_extents () ¤Ï¡¢´Ø¿ô mdraw_text_with_control ()
2354     ¤¬ÉÁ²èÀ©¸æ¥ª¥Ö¥¸¥§¥¯¥È $CONTROL ¤òÍѤ¤¤Æ M-text $MT ¤Î $FROM ¤«¤é $TO 
2355     ¤Þ¤Ç¤ò¥Õ¥ì¡¼¥à $FRAME ¤Ëɽ¼¨¤¹¤ëºÝ¤Î³Æʸ»ú¤Î¥µ¥¤¥º¤ò·×»»¤¹¤ë¡£
2356
2357     $ARRAY_SIZE ¤Ë¤è¤Ã¤Æ $INK_ARRAY_RETURN ¤È$LOGICAL_ARRAY_RETURN 
2358     ¤Î¥µ¥¤¥º¤ò»ØÄꤹ¤ë¡£$INK_ARRAY_RETURN ¤È$LOGICAL_ARRAY_RETURN 
2359     ¤Î³ÆÍ×ÁǤϡ¢¤½¤ì¤¾¤ìʸ»ú¤ÎÉÁ²è¥¤¥ó¥¯¤ÈÏÀÍý¥µ¥¤¥º¡ÊM-text 
2360     ¤Îɽ¼¨¸¶ÅÀ¤«¤é¤ÎÁêÂаÌÃ͡ˤˤè¤Ã¤Æ½ç¤ËËä¤á¤é¤ì¤ë¡£ÀßÄꤵ¤ì¤¿ $INK_ARRAY_RETURN ¤È 
2361     $LOGICAL_ARRAY_RETURN ¤ÎÍ×ÁǤοô¤Ï¡¢$NUM_CHARS_RETURN ¤ËÌᤵ¤ì¤ë¡£
2362    
2363     $ARRAY_SIZE ¤¬¤¹¤Ù¤Æ¤ÎÀ£Ë¡¤òÌ᤻¤Ê¤¤¤Û¤É¾®¤µ¤¤¾ì¹ç¤Ë¤Ï¡¢´Ø¿ô¤Ï -1 
2364     ¤òÊÖ¤·¡¢É¬ÍפÊÂ礭¤µ¤ò $NUM_CHARS_RETURN ¤ËÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð 0 
2365     ¤òÊÖ¤¹¡£
2366
2367     ¥Ý¥¤¥ó¥¿ $OVERALL_INK_RETURN ¤È $OVERALL_LOGICAL_RETURN ¤¬@c NULL 
2368     ¤Ç¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï¥Æ¥­¥¹¥ÈÁ´ÂΤΥµ¥¤¥º¤â·×»»¤·¡¢·ë²Ì¤ò
2369     $OVERALL_INK_RETURN ¤È $OVERALL_LOGICAL_RETURN ¤Ç»Ø¤µ¤ì¤ë¹½Â¤¤Î¥á¥ó¥Ð¤ËÊݸ¤¹¤ë¡£
2370
2371     $CONTROL->two_dimensional ¤¬0¤Ç¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤ÏºÇ½é¤Î¹Ô¤Îʸ»ú¤Î¥µ¥¤¥º¤À¤±¤ò·×»»¤¹¤ë¡£ */
2372
2373 int
2374 mdraw_text_per_char_extents (MFrame *frame,
2375                              MText *mt, int from, int to,
2376                              MDrawControl *control,
2377                              MDrawMetric *ink_array_return,
2378                              MDrawMetric *logical_array_return,
2379                              int array_size,
2380                              int *num_chars_return,
2381                              MDrawMetric *overall_ink_return,
2382                              MDrawMetric *overall_logical_return)
2383 {
2384   MGlyphString *gstring;
2385   MGlyph *g;
2386   int x;
2387
2388   ASSURE_CONTROL (control);
2389   *num_chars_return = to - from;
2390   if (array_size < *num_chars_return)
2391     MERROR (MERROR_DRAW, -1);
2392   if (overall_logical_return)
2393     memset (overall_logical_return, 0, sizeof (MDrawMetric));
2394   if (overall_ink_return)
2395     memset (overall_ink_return, 0, sizeof (MDrawMetric));
2396
2397   M_CHECK_RANGE (mt, from, to, -1, 0);
2398   gstring = get_gstring (frame, mt, from, to, control);
2399   if (! gstring)
2400     {
2401       *num_chars_return = 0;
2402       return 0;
2403     }
2404
2405   for (g = MGLYPH (1), x = 0; g->type != GLYPH_ANCHOR; g++)
2406     if (g->pos >= from && g->pos < to)
2407       {
2408         int start = g->pos;
2409         int end = g->to;
2410         int width = g->width;
2411         int lbearing = g->lbearing;
2412         int rbearing = g->rbearing;
2413         int ascent = g->ascent;
2414         int descent = g->descent;
2415         int logical_ascent;
2416         int logical_descent;
2417
2418         if (g->rface->rfont)
2419           {
2420             logical_ascent = g->rface->rfont->ascent;
2421             logical_descent = g->rface->rfont->descent;
2422           }
2423         else
2424           {
2425             logical_ascent = g->rface->ascent;
2426             logical_descent = g->rface->descent;
2427           }
2428         for (g++; g->type != GLYPH_ANCHOR && g->pos == start; g++)
2429           {
2430             if (lbearing < width + g->lbearing)
2431               lbearing = width + g->lbearing;
2432             if (rbearing < width + g->rbearing)
2433               rbearing = width + g->rbearing;
2434             width += g->width;
2435             if (ascent < g->ascent)
2436               ascent = g->ascent;
2437             if (descent < g->descent)
2438               descent = g->descent;
2439           }
2440
2441         if (end > to)
2442           end = to;
2443         while (start < end)
2444           {
2445             if (ink_array_return)
2446               {
2447                 ink_array_return[start - from].x = x + lbearing;
2448                 ink_array_return[start - from].y = - ascent;
2449                 ink_array_return[start - from].width = rbearing - lbearing;
2450                 ink_array_return[start - from].height = ascent + descent;
2451               }
2452             if (logical_array_return)
2453               {
2454                 logical_array_return[start - from].x = x;
2455                 logical_array_return[start - from].y = - logical_descent;
2456                 logical_array_return[start - from].height
2457                   = logical_ascent + logical_descent;
2458                 logical_array_return[start - from].width = width;
2459               }
2460             start++;
2461           }
2462         x += width;
2463         g--;
2464       }
2465
2466   if (overall_ink_return)
2467     {
2468       overall_ink_return->y = - gstring->line_ascent;
2469       overall_ink_return->x = gstring->lbearing;
2470       overall_ink_return->width = x - gstring->lbearing;
2471       overall_ink_return->height = gstring->height;
2472     }
2473   if (overall_logical_return)
2474     {
2475       overall_logical_return->y = - gstring->ascent;
2476       overall_logical_return->x = 0;
2477       overall_logical_return->width = x;
2478       overall_logical_return->height = gstring->ascent + gstring->descent;
2479     }
2480
2481   M17N_OBJECT_UNREF (gstring->top);
2482   return 0;
2483 }
2484
2485 /*=*/
2486
2487 /***en
2488     @brief Return the character position nearest to the coordinates.
2489
2490     The mdraw_coordinates_position () function checks which character
2491     is to be drawn at coordinate ($X, $Y) when the text between $FROM
2492     and $TO of M-text $MT is drawn at the coordinate (0, 0) using the
2493     mdraw_text_with_control () function with the drawing control
2494     object $CONTROL.  Here, the character position means the number of
2495     characters that precede the character in question in $MT, that is,
2496     the character position of the first character is 0.
2497
2498     $FRAME is used only to get the default face information.
2499
2500     @return
2501     If the glyph image of a character covers coordinate ($X, $Y),
2502     mdraw_coordinates_position () returns the character position of
2503     that character.\n\n
2504     If $Y is less than the minimum Y-coordinate of the drawn area, it
2505     returns $FROM.\n\n
2506     If $Y is greater than the maximum Y-coordinate of the drawn area,
2507     it returns $TO.\n\n
2508     If $Y fits in with the drawn area but $X is less than the minimum
2509     X-coordinate, it returns the character position of the first
2510     character drawn on the line $Y.\n\n
2511     If $Y fits in with the drawn area but $X is greater than the
2512     maximum X-coordinate, it returns the character position of the
2513     last character drawn on the line $Y.  */
2514
2515 /***ja
2516     @brief »ØÄꤷ¤¿ºÂɸ¤ËºÇ¤â¶á¤¤Ê¸»ú¤Îʸ»ú°ÌÃÖ¤òÆÀ¤ë.
2517
2518     ´Ø¿ô mdraw_coordinates_position () ¤Ï¡¢´Ø¿ô 
2519     mdraw_text_with_control () ¤¬ÉÁ²èÀ©¸æ¥ª¥Ö¥¸¥§¥¯¥È $CONTROL ¤òÍѤ¤¤Æ¡¢
2520     M-text $MT ¤Î $FROM ¤«¤é $TO ¤Þ¤Ç¤òºÂɸ (0, 0) 
2521     ¤òµ¯ÅÀ¤È¤·¤ÆÉÁ²è¤¹¤ëºÝ¤Ë¡¢ºÂɸ ($X, $Y) 
2522     ¤ËÉÁ²è¤µ¤ì¤ëʸ»ú¤Îʸ»ú°ÌÃÖ¤òÊÖ¤¹¡£¤³¤³¤Çʸ»ú°ÌÃ֤Ȥϡ¢Åö³º
2523     M-text Ãæ¤Ë¤ª¤¤¤Æ¤½¤Îʸ»ú¤¬ºÇ½é¤«¤é²¿ÈÖÌܤ«¤ò¼¨¤¹À°¿ô¤Ç¤¢¤ë¡£¤¿¤À¤·ºÇ½é¤Îʸ»ú¤Îʸ»ú°ÌÃÖ¤Ï0¤È¤¹¤ë¡£
2524
2525     $FRAME ¤Ï¥Ç¥Õ¥©¥ë¥È¤Î¥Õ¥§¡¼¥¹¤Î¾ðÊó¤òÆÀ¤ë¤¿¤á¤À¤±¤ËÍѤ¤¤é¤ì¤ë¡£
2526
2527     @return
2528     ºÂɸ ($X, $Y) ¤¬¤¢¤ëʸ»ú¤Î¥°¥ê¥Õ¤Çʤ¤ï¤ì¤ë¾ì¹ç¡¢ ´Ø¿ô 
2529     mdraw_coordinates_position () ¤Ï¤½¤Îʸ»ú¤Îʸ»ú°ÌÃÖ¤òÊÖ¤¹¡£\n\n
2530     ¤â¤· $Y ¤¬ÉÁ²èÎΰè¤ÎºÇ¾®YºÂɸ¤è¤ê¤â¾®¤µ¤¤¤Ê¤é¤Ð $FROM ¤òÊÖ¤¹¡£\n\n
2531     ¤â¤· $Y ¤¬ÉÁ²èÎΰè¤ÎºÇÂçYºÂɸ¤è¤ê¤âÂ礭¤¤¤Ê¤é¤Ð $TO ¤òÊÖ¤¹¡£\n\n
2532     ¤â¤· $Y ¤¬ÉÁ²èÎΰè¤Ë¾è¤Ã¤Æ¤¤¤Æ¤«¤Ä $X ¤¬ÉÁ²èÎΰè¤ÎºÇ¾®XºÂɸ¤è¤ê¤â
2533     ¾®¤µ¤¤¾ì¹ç¤Ï¡¢Ä¾Àþ y = $Y ¾å¤ËÉÁ²è¤µ¤ì¤ëºÇ½é¤Îʸ»ú¤Îʸ»ú°ÌÃÖ¤òÊÖ¤¹¡£\n\n
2534     ¤â¤· $Y ¤¬ÉÁ²èÎΰè¤Ë¾è¤Ã¤Æ¤¤¤Æ¤«¤Ä $X ¤¬ÉÁ²èÎΰè¤ÎºÇÂçXºÂɸ¤è¤ê¤â
2535     Â礭¤¤¾ì¹ç¤Ï¡¢Ä¾Àþ y = $Y ¾å¤ËÉÁ²è¤µ¤ì¤ëºÇ¸å¤Îʸ»ú¤Îʸ»ú°ÌÃÖ¤òÊÖ¤¹¡£ */
2536
2537 int
2538 mdraw_coordinates_position (MFrame *frame, MText *mt, int from, int to,
2539                             int x_offset, int y_offset, MDrawControl *control)
2540 {
2541   MGlyphString *gstring;
2542   int y = 0;
2543   int width;
2544   MGlyph *g;
2545
2546   M_CHECK_POS_X (mt, from, -1);
2547   if (to > mtext_nchars (mt) + (control->cursor_width != 0))
2548     to = mtext_nchars (mt) + (control->cursor_width != 0);
2549   else if (to < from)
2550     to = from;
2551
2552   if (from == to)
2553     return from;
2554   ASSURE_CONTROL (control);
2555   gstring = get_gstring (frame, mt, from, to, control);
2556   while (y + gstring->line_descent <= y_offset
2557          && gstring->to < to)
2558     {
2559       from = gstring->to;
2560       y += gstring->line_descent;
2561       M17N_OBJECT_UNREF (gstring->top);
2562       gstring = get_gstring (frame, mt, from, to, control);
2563       y += gstring->line_ascent;
2564     }
2565
2566   /* Accumulate width of glyphs in WIDTH until it exceeds X. */
2567   if (! control->orientation_reversed)
2568     {
2569       width = gstring->indent;
2570       for (g = MGLYPH (1); g->type != GLYPH_ANCHOR; g++)
2571         if (g->pos >= from && g->pos < to)
2572           {
2573             width += g->width;
2574             if (width > x_offset)
2575               break;
2576           }
2577     }
2578   else
2579     {
2580       width = - gstring->indent;
2581       for (g = MGLYPH (gstring->used - 2); g->type != GLYPH_ANCHOR; g--)
2582         if (g->pos >= from && g->pos < to)
2583           {
2584             width -= g->width;
2585             if (width < x_offset)
2586               break;
2587           }
2588     }
2589   if (g->type == GLYPH_ANCHOR
2590       && control->two_dimensional
2591       && g[-1].c == '\n')
2592     g--;
2593   from = g->pos;
2594   M17N_OBJECT_UNREF (gstring->top);
2595
2596   return from;
2597 }
2598
2599 /*=*/
2600
2601 /***en
2602     @brief Compute information about a glyph.
2603
2604     The mdraw_glyph_info () function computes information about a
2605     glyph that covers a character at position $POS of the M-text $MT
2606     assuming that the text is drawn from the character at $FROM of $MT
2607     on a window of frame $FRAME using the mdraw_text_with_control ()
2608     function with the drawing control object $CONTROL.
2609
2610     The information is stored in the members of $INFO.  */
2611 /***ja
2612     @brief ¥°¥ê¥Õ¤Ë´Ø¤¹¤ë¾ðÊó¤ò·×»»¤¹¤ë.
2613
2614     ´Ø¿ô mdraw_glyph_info () ¤Ï¡¢´Ø¿ô mdraw_text_with_control () 
2615     ¤¬ÉÁ ²èÀ©¸æ¥ª¥Ö¥¸¥§¥¯¥È $CONTROL ¤òÍѤ¤¤ÆM-text $MT ¤Î $FROM ¤«¤é $TO 
2616     ¤Þ¤Ç¤ò¥Õ¥ì¡¼¥à $FRAME ¤ËÉÁ²è¤·¤¿¾ì¹ç¡¢M-text ¤Îʸ»ú°ÌÃÖ $POS 
2617     ¤Îʸ»ú¤òʤ¤¦¥°¥ê¥Õ¤Ë´Ø¤¹¤ë¾ðÊó¤ò·×»»¤¹¤ë¡£
2618
2619     ¾ðÊó¤Ï$INFO ¤Î¥á¥ó¥Ð¤ËÊÝ»ý¤µ¤ì¤ë¡£  */
2620
2621 /***
2622     @seealso
2623     MDrawGlyphInfo
2624 */
2625
2626 int
2627 mdraw_glyph_info (MFrame *frame, MText *mt, int from, int pos,
2628                   MDrawControl *control, MDrawGlyphInfo *info)
2629 {
2630   MGlyphString *gstring;
2631   MGlyph *g;
2632   int y = 0;
2633
2634   M_CHECK_RANGE_X (mt, from, pos, -1);
2635
2636   ASSURE_CONTROL (control);
2637   gstring = get_gstring (frame, mt, from, pos + 1, control);
2638   if (! gstring)
2639     MERROR (MERROR_DRAW, -1);
2640   while (gstring->to <= pos)
2641     {
2642       y += gstring->line_descent;
2643       M17N_OBJECT_UNREF (gstring->top);
2644       gstring = get_gstring (frame, mt, gstring->to, pos + 1, control);
2645       y += gstring->line_ascent;
2646     }
2647   info->line_from = gstring->from;
2648   if (info->line_from < from)
2649     info->line_from = from;
2650   info->line_to = gstring->to;
2651
2652   info->y = y;
2653   if (! control->orientation_reversed)
2654     {
2655       info->x = gstring->indent;
2656       for (g = MGLYPH (1); g->pos > pos || g->to <= pos; g++)
2657         info->x += g->width;
2658     }
2659   else
2660     {
2661       info->x = - gstring->indent;
2662       for (g = MGLYPH (gstring->used - 2); g->pos > pos || g->to <= pos; g--)
2663         info->x -= g->width;
2664       while (g[-1].to == g->to)
2665         g--;
2666     }
2667   info->from = g->pos;
2668   info->to = g->to;
2669   info->metrics.x = g->lbearing;
2670   info->metrics.y = - gstring->line_ascent;
2671   info->metrics.height = gstring->height;
2672   info->metrics.width = - g->lbearing + g->width;
2673   if (g->rface->rfont)
2674     info->font = (MFont *) g->rface->rfont;
2675   else
2676     info->font = NULL;
2677   /* info->logical_width is calculated later.  */
2678
2679   if (info->from > info->line_from)
2680     {
2681       /* The logically previous glyph is on this line.  */
2682       MGlyph *g_tmp = find_glyph_in_gstring (gstring, info->from - 1, 1);
2683
2684       info->prev_from = g_tmp->pos;
2685     }
2686   else if (info->line_from > 0
2687            && gstring->from > 0)
2688     {
2689       /* The logically previous glyph is on the previous line.  */
2690       MGlyphString *gst = get_gstring (frame, mt, gstring->from - 1,
2691                                        gstring->from, control);
2692       MGlyph *g_tmp = find_glyph_in_gstring (gst, info->from - 1, 1);
2693
2694       info->prev_from = g_tmp->pos;
2695       M17N_OBJECT_UNREF (gst->top);
2696     }
2697   else
2698     info->prev_from = -1;
2699
2700   if (GLYPH_INDEX (g) > 1)
2701     info->left_from = g[-1].pos, info->left_to = g[-1].to;
2702   else if (! control->orientation_reversed)
2703     {
2704       if (info->line_from > 0)
2705         {
2706           MGlyph *g_tmp;
2707           MGlyphString *gst;
2708           int p = gstring->from - 1;
2709
2710           gst = get_gstring (frame, mt, p, gstring->from, control);
2711           g_tmp = gst->glyphs + (gst->used - 2);
2712           info->left_from = g_tmp->pos, info->left_to = g_tmp->to;
2713           M17N_OBJECT_UNREF (gst->top);
2714         }
2715       else
2716         info->left_from = info->left_to = -1;
2717     }
2718   else
2719     {
2720       if (gstring->to + (control->cursor_width == 0) <= mtext_nchars (mt))
2721         {
2722           MGlyph *g_tmp;
2723           MGlyphString *gst;
2724           int p = gstring->to;
2725
2726           gst = get_gstring (frame, mt, p, p + 1, control);
2727           g_tmp = gst->glyphs + (gst->used - 2);
2728           info->left_from = g_tmp->pos, info->left_to = g_tmp->to;
2729           M17N_OBJECT_UNREF (gst->top);
2730         }
2731       else
2732         info->left_from = info->left_to = -1;
2733     }
2734
2735   if (info->to < gstring->to)
2736     {
2737       /* The logically next glyph is on this line.   */
2738       MGlyph *g_tmp = find_glyph_in_gstring (gstring, info->to, 0);
2739
2740       info->next_to = g_tmp->to;
2741     }
2742   else if (info->to + (control->cursor_width == 0) <= mtext_nchars (mt))
2743     {
2744       /* The logically next glyph is on the next line.   */
2745       int p = info->to;
2746       MGlyphString *gst = get_gstring (frame, mt, p, p + 1, control);
2747       MGlyph *g_tmp = find_glyph_in_gstring (gst, p, 0);
2748
2749       info->next_to = g_tmp->to;
2750       M17N_OBJECT_UNREF (gst->top);
2751     }
2752   else
2753     info->next_to = -1;
2754
2755   for (info->logical_width = (g++)->width;
2756        g->pos == pos && g->type != GLYPH_ANCHOR;
2757        info->metrics.width += g->width, info->logical_width += (g++)->width);
2758   info->metrics.width += g[-1].rbearing - g[-1].width;
2759
2760   if (g->type != GLYPH_ANCHOR)
2761     info->right_from = g->pos, info->right_to = g->to;
2762   else if (! control->orientation_reversed)
2763     {
2764       if (gstring->to + (control->cursor_width == 0) <= mtext_nchars (mt))
2765         {
2766           pos = gstring->to;
2767           M17N_OBJECT_UNREF (gstring->top);
2768           gstring = get_gstring (frame, mt, pos, pos + 1, control);
2769           g = MGLYPH (1);
2770           info->right_from = g->pos, info->right_to = g->to;
2771         }
2772       else
2773         info->right_from = info->right_to = -1;
2774     }
2775   else
2776     {
2777       if (info->line_from > 0)
2778         {
2779           pos = gstring->from - 1;
2780           M17N_OBJECT_UNREF (gstring->top);
2781           gstring = get_gstring (frame, mt, pos, pos + 1, control);
2782           g = MGLYPH (1);
2783           info->right_from = g->pos, info->right_to = g->to;
2784         }
2785       else
2786         info->right_from = info->right_to = -1;
2787     }
2788
2789   M17N_OBJECT_UNREF (gstring->top);
2790   return 0;
2791 }
2792
2793 /*=*/
2794
2795 /***en
2796     @brief Compute information about glyph sequence.
2797
2798     The mdraw_glyph_list () function computes information about glyphs
2799     corresponding to the text between $FROM and $TO of M-text $MT when
2800     it is drawn on a window of frame $FRAME using the
2801     mdraw_text_with_control () function with the drawing control
2802     object $CONTROL.  $GLYPHS is an array of objects to store the
2803     information, and $ARRAY_SIZE is the array size.
2804
2805     If $ARRAY_SIZE is large enough to cover all glyphs, it stores the
2806     number of actually filled elements in the place pointed by
2807     $NUM_GLYPHS_RETURN, and returns 0.
2808
2809     Otherwise, it stores the required array size in the place pointed
2810     by $NUM_GLYPHS_RETURN, and returns -1.  */
2811
2812 /***ja
2813     @brief ¥°¥ê¥ÕÎó¤Ë´Ø¤¹¤ë¾ðÊó¤ò·×»»¤¹¤ë.
2814
2815     ´Ø¿ô mdraw_glyph_list () ¤Ï¡¢´Ø¿ô mdraw_text_with_control () 
2816     ¤¬ÉÁ²èÀ©¸æ¥ª¥Ö¥¸¥§¥¯¥È $CONTROL ¤òÍѤ¤¤ÆM-text $MT ¤Î $FROM ¤«¤é $TO
2817     ¤Þ¤Ç¤ò¥Õ¥ì¡¼¥à $FRAME ¤ËÉÁ²è¤·¤¿¾ì¹ç¤Î¡¢³Æ¥°¥ê¥Õ¤Î¾ðÊó¤ò $GLYPHS 
2818     ¤¬»Ø¤¹ÇÛÎó¤Ë³ÊǼ¤¹¤ë¡£ $ARRAY_SIZE ¤Ï¤½¤ÎÇÛÎó¤Î¥µ¥¤¥º¤Ç¤¢¤ë¡£
2819
2820     ¤â¤· $ARRAY_SIZE ¤¬¤¹¤Ù¤Æ¤Î¥°¥ê¥Õ¤Ë¤Ä¤¤¤Æ¤Î¾ðÊó¤ò³ÊǼ¤¹¤ë¤Î¤Ë½½Ê¬¤Ç¤¢¤ì¤Ð¡¢
2821     $NUM_GLYPHS_RETURN ¤¬»Ø¤¹¾ì½ê¤Ë¼ÂºÝ¤ËËä¤á¤¿Í×ÁǤοô¤òÀßÄꤷ 0 ¤òÊÖ¤¹¡£
2822
2823     
2824     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢$NUM_GLYPHS_RETURN ¤¬»Ø¤¹¾ì½ê¤ËɬÍפÊÇÛÎó¤Î¥µ¥¤¥º¤òÀßÄꤷ¡¢
2825     -1 ¤òÊÖ¤¹¡£
2826     */
2827
2828 /***
2829     @seealso
2830     MDrawGlyph
2831 */
2832
2833 int
2834 mdraw_glyph_list (MFrame *frame, MText *mt, int from, int to,
2835                   MDrawControl *control, MDrawGlyph *glyphs,
2836                   int array_size, int *num_glyphs_return)
2837 {
2838   MGlyphString *gstring;
2839   MGlyph *g;
2840   int n;
2841   int pad_width = 0;
2842
2843   ASSURE_CONTROL (control);
2844   *num_glyphs_return = 0;
2845   M_CHECK_RANGE (mt, from, to, -1, 0);
2846   gstring = get_gstring (frame, mt, from, to, control);
2847   if (! gstring)
2848     return -1;
2849   for (g = MGLYPH (1), n = 0; g->type != GLYPH_ANCHOR; g++)
2850     {
2851       if (g->type == GLYPH_BOX
2852           || g->pos < from || g->pos >= to)
2853         continue;
2854       if (g->type == GLYPH_PAD)
2855         {
2856           if (g->left_padding)
2857             pad_width = g->width;
2858           else if (n > 0)
2859             {
2860               pad_width = 0;
2861               glyphs[-1].x_advance += g->width;
2862             }
2863           continue;
2864         }
2865       if (n < array_size)
2866         {
2867           glyphs->from = g->pos;
2868           glyphs->to = g->to;
2869           glyphs->glyph_code = g->code;
2870           glyphs->x_off = g->xoff + pad_width;
2871           glyphs->y_off = g->yoff;
2872           glyphs->lbearing = g->lbearing;
2873           glyphs->rbearing = g->rbearing;
2874           glyphs->ascent = g->ascent;
2875           glyphs->descent = g->descent;
2876           glyphs->x_advance = g->width + pad_width;
2877           glyphs->y_advance = 0;
2878           if (g->rface->rfont)
2879             {
2880               glyphs->font = (MFont *) g->rface->rfont;
2881               glyphs->font_type
2882                 = (glyphs->font->source == MFONT_SOURCE_X ? Mx
2883                    : g->rface->rfont->driver == &mfont__ft_driver ? Mfreetype
2884                    : Mxft);
2885               glyphs->fontp = g->rface->rfont->fontp;
2886             }
2887           else
2888             {
2889               glyphs->font = NULL;
2890               glyphs->font_type = Mnil;
2891               glyphs->fontp = NULL;
2892             }
2893           pad_width = 0;
2894           glyphs++;
2895         }
2896       n++;
2897     }
2898   M17N_OBJECT_UNREF (gstring->top);
2899
2900   *num_glyphs_return = n;
2901   return (n <= array_size ? 0 : -1);
2902 }
2903
2904 /*=*/
2905
2906 /***en
2907     @brief Draw one or more textitems.
2908
2909     The mdraw_text_items () function draws one or more M-texts on
2910     window $WIN of frame $FRAME at coordinate ($X, $Y).  $ITEMS is an array
2911     of the textitems to be drawn and $NITEMS is the number of
2912     textitems in the array.  */
2913
2914 /***ja
2915     @brief textitem ¤òɽ¼¨¤¹¤ë.
2916
2917     ´Ø¿ô mdraw_text_items () ¤Ï¡¢°ì¸Ä°Ê¾å¤Î¥Æ¥­¥¹¥È¥¢¥¤¥Æ¥à¤ò¡¢¥Õ¥ì¡¼¥à
2918     $FRAME ¤Î¥¦¥£¥ó¥É¥¦ $WIN ¤ÎºÂɸ ($X, $Y) ¤Ëɽ¼¨¤¹¤ë¡£$ITEMS 
2919     ¤Ïɽ¼¨¤¹¤Ù¤­¥Æ¥­¥¹¥È¥¢¥¤¥Æ¥à¤ÎÇÛÎó¤Ç¤¢¤ê¡¢$NITEMS ¤Ï¤½¤Î¸Ä¿ô¤Ç¤¢¤ë¡£
2920
2921     @latexonly \IPAlabel{mdraw_text_items} @endlatexonly  */
2922
2923 /***
2924     @seealso
2925     MTextItem, mdraw_text ().  */
2926
2927 void
2928 mdraw_text_items (MFrame *frame, MDrawWindow win, int x, int y,
2929                   MDrawTextItem *items, int nitems)
2930 {
2931   if (! (frame->device_type & MDEVICE_SUPPORT_OUTPUT))
2932     return;
2933   while (nitems-- > 0)
2934     {
2935       if (items->face)
2936         mtext_push_prop (items->mt, 0, mtext_nchars (items->mt), Mface,
2937                          items->face);
2938       mdraw_text_with_control (frame, win, x, y,
2939                                items->mt, 0, mtext_nchars (items->mt),
2940                                items->control);
2941       x += mdraw_text_extents (frame, items->mt, 0, mtext_nchars (items->mt),
2942                                items->control, NULL, NULL, NULL);
2943       x += items->delta;
2944       if (items->face)
2945         mtext_pop_prop (items->mt, 0, mtext_nchars (items->mt), Mface);
2946     }
2947 }
2948
2949 /*=*/
2950 /***en
2951     @brief Option of line breaking for drawing text.
2952
2953     The variable #mdraw_line_break_option specifies line breaking
2954     options by logical-or of the members of #MTextLineBreakOption.  It
2955     controls the line breaking algorithm of the function
2956     mdraw_default_line_break ().  */
2957     
2958 int mdraw_line_break_option;
2959
2960 /*=*/
2961 /***en 
2962     @brief Calculate a line breaking position.
2963
2964     The function mdraw_default_line_break () calculates a line
2965     breaking position based on the line number $LINE and the
2966     coordinate $Y, when a line is too long to fit within the width
2967     limit.  $POS is the position of the character next to the last one
2968     that fits within the limit.  $FROM is the position of the first
2969     character of the line, and $TO is the position of the last
2970     character displayed on the line if there were not width limit.
2971     $LINE and $Y are reset to 0 when a line is broken by a newline
2972     character, and incremented each time when a long line is broken
2973     because of the width limit.
2974
2975     @return This function returns a character position to break the
2976     line.
2977 */
2978
2979 /***ja 
2980       @brief ²þ¹Ô°ÌÃÖ¤ò·×»»¤¹¤ë.
2981
2982       ´Ø¿ô mdraw_default_line_break () ¤Ï¡¢¹Ô¤¬ºÇÂçÉýÃæ¤Ë¼ý¤Þ¤é¤Ê¤¤¾ì¹ç¤Î²þ¹Ô°ÌÃÖ¤ò¡¢¹ÔÈÖ¹æ
2983       $LINE ¤ÈºÂɸ $Y ¤Ë´ð¤Å¤¤¤Æ·×»»¤¹¤ë¡£
2984       $POS ¤ÏºÇÂçÉý¤Ë¼ý¤Þ¤ëºÇ¸å¤Îʸ»ú¤Î¼¡¤Îʸ»ú¤Î°ÌÃ֤Ǥ¢¤ë¡£
2985       $FROM ¤Ï¤½¤Î¹Ô¤ÎºÇ½é¤Îʸ»ú¤Î°ÌÃÖ¡¢$TO 
2986       ¤ÏºÇÂçÉý¤¬»ØÄꤵ¤ì¤Æ¤¤¤Ê¤±¤ì¤Ð¤½¤Î¹Ô¤Ëɽ¼¨¤µ¤ì¤ëºÇ¸å¤Îʸ»ú¤Î°ÌÃ֤Ǥ¢¤ë¡£
2987       $LINE ¤È $Y ¤Ï²þ¹Ôʸ»ú¤Ë¤è¤Ã¤Æ¹Ô¤¬²þ¤Þ¤Ã¤¿ºÝ¤Ë¤Ï 0
2988       ¤Ë¥ê¥»¥Ã¥È¤µ¤ì¡¢ºÇÂçÉý¤Ë¤è¤Ã¤Æ¹Ô¤¬²þ¤Þ¤Ã¤¿¾ì¹ç¤Ë¤Ï 1 ¤Å¤ÄÁý¤ä¤µ¤ì¤ë¡£
2989
2990       @return 
2991       ¤³¤Î´Ø¿ô¤Ï²þ¹Ô¤¹¤ëʸ»ú°ÌÃÖ¤òÊÖ¤¹¡£
2992 */
2993
2994 int
2995 mdraw_default_line_break (MText *mt, int pos,
2996                           int from, int to, int line, int y)
2997 {
2998   int p, after;
2999
3000   p = mtext_line_break (mt, pos, mdraw_line_break_option, &after);
3001   if (p < from)
3002     p = from;
3003   else if (p >= to)
3004     p = to;
3005   return p;
3006 }
3007
3008 /*=*/
3009
3010 /***en
3011     @brief Obtain per character dimension information.
3012
3013     The mdraw_per_char_extents () function computes the text dimension
3014     of each character in M-text $MT.  The faces given as text
3015     properties in $MT and the default face of frame $FRAME determine
3016     the fonts to draw the text.  Each successive element in
3017     $ARRAY_RETURN is set to the drawn metrics of successive
3018     characters, which is relative to the origin of the drawing, and a
3019     rectangle for each character in $MT.  The number of elements of
3020     $ARRAY_RETURN must be equal to or greater than the number of
3021     characters in $MT.
3022
3023     If pointer $OVERALL_RETURN is not @c NULL, this function also
3024     computes the extents of the overall text and stores the results in
3025     the members of the structure pointed to by $OVERALL_RETURN.  */
3026
3027 /***ja
3028     @brief M-text ¤Îʸ»úËè¤Îɽ¼¨ÈϰϾðÊó¤òÆÀ¤ë.
3029
3030     ´Ø¿ô mdraw_per_char_extents () ¤Ï¡¢M-text $MT 
3031     Ãæ¤Î³Æʸ»ú¤Îɽ¼¨ÈϰϤò·×»»¤¹¤ë¡£¤³¤Î·×»»¤ËÍѤ¤¤ë¥Õ¥©¥ó¥È¤Ï¡¢
3032     $MT ¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ç»ØÄꤵ¤ì¤¿¥Õ¥§¡¼¥¹¤È¡¢¥Õ¥ì¡¼¥à $FRAME
3033     ¤Î¥Ç¥Õ¥©¥ë¥È¥Õ¥§¡¼¥¹¤Ë¤è¤Ã¤Æ·è¤Þ¤ë¡£$ARRAY_RETURN ¤Î³ÆÍ×ÁǤϡ¢$MT
3034     Ãæ¤Î³Æʸ»ú¤Îɽ¼¨ÈϰϾðÊó¤Ë¤è¤Ã¤Æ½ç¤ËËä¤á¤é¤ì¤ë¡£É½¼¨ÈϰϾðÊó¤È¤Ï¡¢
3035     É½¼¨¸¶ÅÀ¤«¤é¤ÎÁêÂаÌÃ֤ȳÆʸ»ú¤ÎÀê¤á¤ëĹÊý·Á¤Ç¤¢¤ë¡£$ARRAY_RETURN 
3036     ¤ÎÍ×ÁÇ¿ô¤Ï¡¢M-text Ãæ¤Îʸ»ú¿ô°Ê¾å¤Ç¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£
3037
3038     ¥Ý¥¤¥ó¥¿ $OVERALL_RETURN ¤¬ @c NULL 
3039     ¤Ç¤Ê¤¤¾ì¹ç¤Ï¡¢¥Æ¥­¥¹¥ÈÁ´ÂΤÎɽ¼¨ÈϰϾðÊó¤â·×»»¤·¡¢¤½¤Î·ë²Ì¤ò 
3040     $OVERALL_RETURN ¤Î»Ø¤¹¹½Â¤ÂΤ˳ÊǼ¤¹¤ë¡£
3041
3042     @latexonly \IPAlabel{mdraw_per_char_extents} @endlatexonly  */
3043
3044 void
3045 mdraw_per_char_extents (MFrame *frame, MText *mt,
3046                         MDrawMetric *array_return,
3047                         MDrawMetric *overall_return)
3048 {
3049   int n = mtext_nchars (mt);
3050
3051   mdraw_text_per_char_extents (frame, mt, 0, n, NULL, array_return, NULL,
3052                                n, &n, overall_return, NULL);
3053 }
3054
3055 /***en 
3056     @brief clear cached information.    
3057
3058     The mdraw_clear_cache () function clear cached information
3059     on M-text $MT that was attached by any of the drawing functions.
3060     When the behavior of `format' or `line_break'
3061     member functions of MDrawControl is changed, the cache must be cleared.
3062
3063     @seealso
3064     MDrawControl */
3065 /***ja 
3066     @brief ¥­¥ã¥Ã¥·¥å¾ðÊó¤ò¾Ã¤¹.
3067
3068     ´Ø¿ô mdraw_clear_cache () ¤ÏÉÁ²è´Ø¿ô¤Ë¤è¤Ã¤Æ M-text $MT 
3069     ¤ËÉղ䵤줿¥­¥ã¥Ã¥·¥å¾ðÊó¤ò¤¹¤Ù¤Æ¾Ãµî¤¹¤ë¡£MDrawControl ¤Î `format' 
3070     ¤¢¤ë¤¤¤Ï `line_break' 
3071     ¥á¥ó¥Ð´Ø¿ô¤Î¿¶Éñ¤¤¤¬ÊѤï¤Ã¤¿¾ì¹ç¤Ë¤Ï¥­¥ã¥Ã¥·¥å¤ò¾Ãµî¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
3072
3073     @seealso
3074     MDrawControl */
3075
3076 void
3077 mdraw_clear_cache (MText *mt)
3078 {
3079   mtext_pop_prop (mt, 0, mtext_nchars (mt), M_glyph_string);
3080 }
3081
3082 /*** @} */
3083
3084 /*
3085   Local Variables:
3086   coding: euc-japan
3087   End:
3088 */