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