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