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