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