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