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