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