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