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