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