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