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