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