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