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