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