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