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