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