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