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