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