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