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