1 /* "$Id: utf8Wrap.c 8401 2011-02-08 10:06:19Z ianmacarthur $"
2 *
3 * Author: Jean-Marc Lienher ( http://oksid.ch )
4 * Copyright 2000-2003 by O'ksi'D.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 * USA.
20 *
21 * Please report all bugs and problems on the following page:
22 *
23 * http://www.fltk.org/str.php
24 */
25
26 /*
27 * X11 UTF-8 text drawing functions.
28 */
29 #if !defined(WIN32) && !defined(__APPLE__)
30
31 #include "../../FL/Xutf8.h"
32 #include <X11/Xlib.h>
33 #include <ctype.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <stdio.h>
37
38 /* External auto generated functions : */
39 #include "ucs2fontmap.c"
40 /*
41 * extern int ucs2fontmap(char *s, unsigned int ucs, int enc);
42 * extern int encoding_number(const char *enc);
43 * extern const char *encoding_name(int num);
44 */
45
46 /* The ARM header files have a bug by not taking into account that ARM cpu
47 * likes pacing to 4 bytes. This little trick defines our own version of
48 * XChar2b which does not have this problem
49 */
50
51 #if defined(__GNUC__) && defined(__arm__) && !defined(__ARM_EABI__)
52 typedef struct {
53 unsigned char byte1;
54 unsigned char byte2;
55 }
56 __attribute__ ((packed))
57 Fl_XChar2b;
58 #else
59 #define Fl_XChar2b XChar2b
60 #endif
61
62
63 /*********************************************************************/
64 /** extract a list of font from the base font name list **/
65 /*********************************************************************/
66 static int
get_font_list(const char * base_font_name_list,char *** flist)67 get_font_list(
68 const char *base_font_name_list,
69 char ***flist) {
70 const char *ptr;
71 const char *p;
72 int nb;
73 int nb_name;
74
75 ptr = base_font_name_list;
76 p = NULL;
77 nb = 0;
78 nb_name = 1;
79
80 while (*ptr) {
81 if (*ptr == ',') nb_name++;
82 ptr++;
83 }
84
85 *flist = (char **) malloc(sizeof(char*) * nb_name);
86 ptr = base_font_name_list;
87
88 while (*ptr) {
89 int l = 0, i = 0;
90
91 while(isspace(*ptr)) ptr++;
92 p = ptr;
93 while (*ptr && *ptr != ',') { ptr++; l++; }
94 if (l > 2) {
95 (*flist)[nb] = (char*) malloc((unsigned)l + 2);
96 while (p != ptr) { ((*flist)[nb])[i] = *p; i++; p++; }
97 (*flist)[nb][i] = '\0';
98 nb++;
99 }
100 if (*ptr) ptr++;
101 }
102 if (nb < 1) {
103 free(*flist);
104 *flist = (char**)NULL;
105 }
106 return nb;
107 }
108
109 /*********************************************************************/
110 /** get the font name used as encoding for "fontspecific" encoding **/
111 /** (mainly used for adobe-symbol and adobe-zapfdingbats) **/
112 /*********************************************************************/
113 static int
font_spec_enc(char * font)114 font_spec_enc(char *font) {
115 int ret;
116 char *enc;
117 char *end;
118
119 enc = font;
120 while (*enc != '-') enc++;
121 enc++;
122 while (*enc != '-') enc++;
123 enc++;
124 end = enc;
125 while (*end != '-') end++;
126 *end = '\0';
127
128 ret = encoding_number(enc);
129 *end = '-';
130
131 return ret;
132 }
133
134
135 /*********************************************************************/
136 /** get the sub range of a iso10646-1 font **/
137 /*********************************************************************/
138 static void
get_range(const char * enc,int * min,int * max)139 get_range(const char *enc,
140 int *min,
141 int *max) {
142
143 const char *ptr = enc;
144 const char *ptr1;
145
146 if (!enc) return;
147
148 while (*ptr && *ptr != '-') ptr++;
149 if (!*ptr) return;
150 while (*ptr && *ptr != '[') ptr++;
151 if (!*ptr) return;
152 *min = 0xFFFF;
153 *max = 0;
154 while (*ptr && *ptr != ']') {
155 int val;
156 ptr++;
157 ptr1 = ptr;
158 while (*ptr && *ptr != ']' && *ptr != ' ' && *ptr != '_') ptr++;
159 val = strtol(ptr1, NULL, 0);
160 if (val < *min) *min = val;
161 if (val > *max) *max = val;
162 }
163 }
164
165 /*********************************************************************/
166 /** get the internal encoding number of each fonts **/
167 /*********************************************************************/
168 static int *
get_encodings(char ** font_name_list,int * ranges,int nb_font)169 get_encodings(char **font_name_list,
170 int *ranges,
171 int nb_font) {
172
173 int *font_encoding_list;
174 int i;
175 i = 0;
176
177 font_encoding_list = (int *) malloc(sizeof(int) * nb_font);
178 while (i < nb_font) {
179 char *ptr;
180 int ec;
181 ptr = font_name_list[i];
182 ec = 0;
183 font_encoding_list[i] = -1;
184 ranges[i * 2] = 0;
185 ranges[i * 2 + 1] = 0xFFFF;
186
187 if (ptr && strstr(ptr, "fontspecific")) {
188 font_encoding_list[i] = font_spec_enc(ptr);
189 ptr = NULL;
190 }
191 while (ptr && *ptr) {
192 if (*ptr == '-') {
193 ec++;
194 if (ec == 13) {
195 font_encoding_list[i] = encoding_number(ptr + 1);
196 if (font_encoding_list[i] == 0) {
197 get_range(ptr + 1,
198 ranges + i * 2,
199 ranges + i * 2 + 1);
200 }
201 break;
202 }
203 }
204 ptr++;
205 }
206 if (font_encoding_list[i] < 0) font_encoding_list[i] = 1;
207 i++;
208 }
209 return font_encoding_list;
210 }
211
212 /*********************************************************************/
213 /** find the first font which matches the name and load it. **/
214 /*********************************************************************/
215 XFontStruct *
find_best_font(Display * dpy,char ** name)216 find_best_font(Display *dpy,
217 char **name) {
218
219 char **list;
220 int cnt;
221 XFontStruct *s;
222
223 list = XListFonts(dpy, *name, 1, &cnt);
224 if (cnt && list) {
225 free(*name);
226 *name = strdup(list[0]);
227 s = XLoadQueryFont(dpy, *name);
228 XFreeFontNames(list);
229 return s;
230 }
231 return NULL;
232 }
233
234 /*********************************************************************/
235 /** load all fonts **/
236 /*********************************************************************/
237 static void
load_fonts(Display * dpy,XUtf8FontStruct * font_set)238 load_fonts(Display *dpy,
239 XUtf8FontStruct *font_set) {
240
241 int i;
242 char **list;
243
244 i = 0;
245 list = NULL;
246
247 font_set->fonts = (XFontStruct**) malloc(sizeof(XFontStruct*) *
248 font_set->nb_font);
249
250 font_set->ranges = (int*) malloc(sizeof(int) *
251 font_set->nb_font * 2);
252
253 font_set->descent = 0;
254 font_set->ascent = 0;
255 font_set->fid = 0;
256
257 while (i < font_set->nb_font) {
258 XFontStruct *fnt;
259
260 fnt = font_set->fonts[i] =
261 find_best_font(dpy, &(font_set->font_name_list[i]));
262 if (fnt) {
263 font_set->fid = fnt->fid;
264 if (fnt->ascent > font_set->ascent) {
265 font_set->ascent = fnt->ascent;
266 }
267 if (fnt->descent > font_set->descent) {
268 font_set->descent = fnt->descent;
269 }
270 } else {
271 free(font_set->font_name_list[i]);
272 font_set->font_name_list[i] = NULL;
273 }
274 i++;
275 }
276
277 font_set->encodings =
278 get_encodings(font_set->font_name_list,
279 font_set->ranges, font_set->nb_font);
280
281 /* unload fonts with same encoding */
282 for (i = 0; i < font_set->nb_font; i++) {
283 if (font_set->font_name_list[i]) {
284 int j;
285 for (j = 0; j < i; j++) {
286 if (font_set->font_name_list[j] &&
287 font_set->encodings[j] ==
288 font_set->encodings[i] &&
289 font_set->ranges[2*j] ==
290 font_set->ranges[2*i] &&
291 font_set->ranges[(2*j)+1] &&
292 font_set->ranges[(2*i)+1]) {
293 XFreeFont(dpy, font_set->fonts[i]);
294 free(font_set->font_name_list[i]);
295 font_set->font_name_list[i] = NULL;
296 font_set->fonts[i] = 0;
297 }
298 }
299 }
300 }
301 }
302
303 /*********************************************************************/
304 /** Creates an array of XFontStruct acording to the comma separated **/
305 /** list of fonts. XLoad all fonts. **/
306 /*********************************************************************/
307 XUtf8FontStruct *
XCreateUtf8FontStruct(Display * dpy,const char * base_font_name_list)308 XCreateUtf8FontStruct(Display *dpy,
309 const char *base_font_name_list) {
310
311 XUtf8FontStruct *font_set;
312
313 font_set = (XUtf8FontStruct*)malloc(sizeof(XUtf8FontStruct));
314
315 if (!font_set) {
316 return NULL;
317 }
318
319 font_set->nb_font = get_font_list(base_font_name_list,
320 &font_set->font_name_list);
321
322 if (font_set->nb_font < 1) {
323 free(font_set);
324 return NULL;
325 }
326
327 load_fonts(dpy, font_set);
328
329 return font_set;
330 }
331
332
333 /*****************************************************************************/
334 /** draw a Right To Left UTF-8 string using multiple fonts as needed. **/
335 /*****************************************************************************/
336 void
XUtf8DrawRtlString(Display * display,Drawable d,XUtf8FontStruct * font_set,GC gc,int x,int y,const char * string,int num_bytes)337 XUtf8DrawRtlString(Display *display,
338 Drawable d,
339 XUtf8FontStruct *font_set,
340 GC gc,
341 int x,
342 int y,
343 const char *string,
344 int num_bytes) {
345
346 int *encodings; /* encodings array */
347 XFontStruct **fonts; /* fonts array */
348 Fl_XChar2b buf[128]; /* drawing buffer */
349 Fl_XChar2b *ptr; /* pointer to the drawing buffer */
350 int fnum; /* index of the current font in the fonts array*/
351 int i; /* current byte in the XChar2b buffer */
352 int first; /* first valid font index */
353 int last_fnum; /* font index of the previous char */
354 int nb_font; /* quantity of fonts in the font array */
355 char glyph[2]; /* byte1 and byte2 value of the UTF-8 char */
356 int *ranges; /* sub range of iso10646 */
357
358 nb_font = font_set->nb_font;
359
360 if (nb_font < 1) {
361 /* there is no font in the font_set :-( */
362 return;
363 }
364
365 ranges = font_set->ranges;
366 fonts = font_set->fonts;
367 encodings = font_set->encodings;
368 i = 0;
369 fnum = 0;
370 ptr = buf + 128;
371
372 while(fnum < nb_font && !fonts[fnum]) fnum++;
373 if (fnum >= nb_font) {
374 /* there is no valid font for the X server */
375 return;
376 }
377
378 first = fnum;
379 last_fnum = fnum;
380
381 while (num_bytes > 0) {
382 int ulen; /* byte length of the UTF-8 char */
383 unsigned int ucs; /* Unicode value of the UTF-8 char */
384 unsigned int no_spc; /* Spacing char equivalent of a non-spacing char */
385
386 if (i > 120) {
387 /*** draw the buffer **/
388 XSetFont(display, gc, fonts[fnum]->fid);
389 x -= XTextWidth16(fonts[fnum], ptr, i);
390 XDrawString16(display, d, gc, x, y, ptr, i);
391 i = 0;
392 ptr = buf + 128;
393 }
394
395 ulen = XFastConvertUtf8ToUcs((unsigned char*)string, num_bytes, &ucs);
396
397 if (ulen < 1) ulen = 1;
398
399 no_spc = XUtf8IsNonSpacing(ucs);
400 if (no_spc) ucs = no_spc;
401
402 /*
403 * find the first encoding which can be used to
404 * draw the glyph
405 */
406 fnum = first;
407 while (fnum < nb_font) {
408 if (fonts[fnum] && ucs2fontmap(glyph, ucs, encodings[fnum]) >= 0) {
409 if (encodings[fnum] != 0 ||
410 (ucs >= ranges[fnum * 2] && ucs <= ranges[fnum * 2 + 1])) {
411 break;
412 }
413 }
414 fnum++;
415 }
416 if (fnum == nb_font) {
417 /* the char is not valid in all encodings ->
418 * draw it using the first font :-(
419 */
420 fnum = first;
421 ucs2fontmap(glyph, '?', encodings[fnum]);
422 }
423
424 if (last_fnum != fnum || no_spc) {
425 XSetFont(display, gc, fonts[last_fnum]->fid);
426 x -= XTextWidth16(fonts[last_fnum], ptr, i);
427 XDrawString16(display, d, gc, x, y, ptr, i);
428 i = 0;
429 ptr = buf + 127;
430 (*ptr).byte1 = glyph[0];
431 (*ptr).byte2 = glyph[1];
432 if (no_spc) {
433 x += XTextWidth16(fonts[fnum], ptr, 1);
434 }
435 } else {
436 ptr--;
437 (*ptr).byte1 = glyph[0];
438 (*ptr).byte2 = glyph[1];
439 }
440 last_fnum = fnum;
441 i++;
442 string += ulen;
443 num_bytes -= ulen;
444 }
445
446 if (i < 1) return;
447
448 XSetFont(display, gc, fonts[fnum]->fid);
449 x -= XTextWidth16(fonts[last_fnum], ptr, i);
450 XDrawString16(display, d, gc, x, y, ptr, i);
451 }
452
453
454 /*****************************************************************************/
455 /** draw an UTF-8 string using multiple fonts as needed. **/
456 /*****************************************************************************/
457 void
XUtf8DrawString(Display * display,Drawable d,XUtf8FontStruct * font_set,GC gc,int x,int y,const char * string,int num_bytes)458 XUtf8DrawString(Display *display,
459 Drawable d,
460 XUtf8FontStruct *font_set,
461 GC gc,
462 int x,
463 int y,
464 const char *string,
465 int num_bytes) {
466
467 int *encodings; /* encodings array */
468 XFontStruct **fonts; /* fonts array */
469 Fl_XChar2b buf[128]; /* drawing buffer */
470 int fnum; /* index of the current font in the fonts array*/
471 int i; /* current byte in the XChar2b buffer */
472 int first; /* first valid font index */
473 int last_fnum; /* font index of the previous char */
474 int nb_font; /* quantity of fonts in the font array */
475 char glyph[2]; /* byte1 and byte2 value of the UTF-8 char */
476 int *ranges; /* sub range of iso10646 */
477
478 nb_font = font_set->nb_font;
479
480 if (nb_font < 1) {
481 /* there is no font in the font_set :-( */
482 return;
483 }
484 ranges = font_set->ranges;
485 fonts = font_set->fonts;
486 encodings = font_set->encodings;
487 i = 0;
488 fnum = 0;
489
490 while(fnum < nb_font && !fonts[fnum]) fnum++;
491 if (fnum >= nb_font) {
492 /* there is no valid font for the X server */
493 return;
494 }
495
496 first = fnum;
497 last_fnum = fnum;
498
499 while (num_bytes > 0) {
500 int ulen; /* byte length of the UTF-8 char */
501 unsigned int ucs; /* Unicode value of the UTF-8 char */
502 unsigned int no_spc; /* Spacing char equivalent of a non-spacing char */
503
504 if (i > 120) {
505 /*** draw the buffer **/
506 XSetFont(display, gc, fonts[fnum]->fid);
507 XDrawString16(display, d, gc, x, y, buf, i);
508 x += XTextWidth16(fonts[fnum], buf, i);
509 i = 0;
510 }
511
512 ulen = XFastConvertUtf8ToUcs((unsigned char*)string, num_bytes, &ucs);
513
514 if (ulen < 1) ulen = 1;
515
516 no_spc = XUtf8IsNonSpacing(ucs);
517 if (no_spc) ucs = no_spc;
518
519 /*
520 * find the first encoding which can be used to
521 * draw the glyph
522 */
523 fnum = first;
524 while (fnum < nb_font) {
525 if (fonts[fnum] && ucs2fontmap(glyph, ucs, encodings[fnum]) >= 0) {
526 if (encodings[fnum] != 0 ||
527 (ucs >= ranges[fnum * 2] &&
528 ucs <= ranges[fnum * 2 + 1])) {
529 break;
530 }
531 }
532 fnum++;
533 }
534 if (fnum == nb_font) {
535 /* the char is not valid in all encodings ->
536 * draw it using the first font :-(
537 */
538 fnum = first;
539 ucs2fontmap(glyph, '?', encodings[fnum]);
540 }
541
542 if (last_fnum != fnum || no_spc) {
543 XSetFont(display, gc, fonts[last_fnum]->fid);
544 XDrawString16(display, d, gc, x, y, buf, i);
545 x += XTextWidth16(fonts[last_fnum], buf, i);
546 i = 0;
547 (*buf).byte1 = glyph[0];
548 (*buf).byte2 = glyph[1];
549 if (no_spc) {
550 x -= XTextWidth16(fonts[fnum], buf, 1);
551 }
552 } else {
553 (*(buf + i)).byte1 = glyph[0];
554 (*(buf + i)).byte2 = glyph[1];
555 }
556 last_fnum = fnum;
557 i++;
558 string += ulen;
559 num_bytes -= ulen;
560 }
561
562 XSetFont(display, gc, fonts[fnum]->fid);
563 XDrawString16(display, d, gc, x, y, buf, i);
564 }
565
566
567 /*****************************************************************************/
568 /** Measure the inked extents of a UTF-8 string using multiple fonts as **/
569 /** needed. Tries to mirror the behaviour of the draw function **/
570 /** XUtf8DrawString() as closely as possible to get consistent sizes. **/
571 /*****************************************************************************/
572 void
XUtf8_measure_extents(Display * display,Drawable d,XUtf8FontStruct * font_set,GC gc,int * xx,int * yy,int * ww,int * hh,const char * string,int num_bytes)573 XUtf8_measure_extents(
574 Display *display,
575 Drawable d,
576 XUtf8FontStruct *font_set,
577 GC gc,
578 int *xx, /* x-offset from origin */
579 int *yy, /* y-offset from origin */
580 int *ww, /* overall inked width */
581 int *hh, /* maximum inked height */
582 const char *string, /* text to measure */
583 int num_bytes) {
584 int *encodings; /* encodings array */
585 XFontStruct **fonts; /* fonts array */
586 Fl_XChar2b buf[128]; /* drawing buffer */
587 int fnum; /* index of the current font in the fonts array*/
588 int i; /* current byte in the XChar2b buffer */
589 int first; /* first valid font index */
590 int last_fnum; /* font index of the previous char */
591 int nb_font; /* quantity of fonts in the font array */
592 char glyph[2]; /* byte1 and byte2 value of the UTF-8 char */
593 int *ranges; /* sub range of iso10646 */
594
595 int wd = 0; /* accumulates the width of the text */
596 int ht = 0; /* used to find max height in text */
597 int hs; /* "height sum" of current text segment */
598 int yt = 0x7FFFFFFF; /* used to find bounding rectangle delta-y */
599 int res; /* result from calling XTextExtents16() - we should test this is OK! */
600
601 XCharStruct sizes;
602 int dir_ret = 0;
603 int fnt_asc = 0;
604 int fnt_dsc = 0;
605
606 nb_font = font_set->nb_font;
607
608 if (nb_font < 1) {
609 /* there is no font in the font_set :-( */
610 return;
611 }
612 ranges = font_set->ranges;
613 fonts = font_set->fonts;
614 encodings = font_set->encodings;
615 i = 0;
616 fnum = 0;
617
618 while(fnum < nb_font && !fonts[fnum]) fnum++;
619 if (fnum >= nb_font) {
620 /* there is no valid font for the X server */
621 return;
622 }
623
624 first = fnum;
625 last_fnum = fnum;
626
627 while (num_bytes > 0) {
628 int ulen; /* byte length of the UTF-8 char */
629 unsigned int ucs; /* Unicode value of the UTF-8 char */
630 unsigned int no_spc; /* Spacing char equivalent of a non-spacing char */
631
632 if (i > 120) {
633 /*** draw the buffer **/
634 XSetFont(display, gc, fonts[fnum]->fid);
635 res = XTextExtents16(fonts[fnum], buf, i, &dir_ret, &fnt_asc, &fnt_dsc, &sizes);
636 /* recover the dimensions - should verify that res == 0 first! */
637 wd += sizes.width; /* accumulate the width */
638 hs = sizes.ascent + sizes.descent; /* total height */
639 if(hs > ht) ht = hs; /* new height exceeds previous height */
640 if(yt > (-sizes.ascent)) yt = -sizes.ascent; /* delta y offset */
641 i = 0;
642 }
643
644 ulen = XFastConvertUtf8ToUcs((unsigned char*)string, num_bytes, &ucs);
645
646 if (ulen < 1) ulen = 1;
647
648 no_spc = XUtf8IsNonSpacing(ucs);
649 if (no_spc) ucs = no_spc;
650
651 /*
652 * find the first encoding which can be used to
653 * draw the glyph
654 */
655 fnum = first;
656 while (fnum < nb_font) {
657 if (fonts[fnum] && ucs2fontmap(glyph, ucs, encodings[fnum]) >= 0) {
658 if (encodings[fnum] != 0 ||
659 (ucs >= ranges[fnum * 2] &&
660 ucs <= ranges[fnum * 2 + 1])) {
661 break;
662 }
663 }
664 fnum++;
665 }
666 if (fnum == nb_font) {
667 /* the char is not valid in all encodings ->
668 * draw it using the first font :-(
669 */
670 fnum = first;
671 ucs2fontmap(glyph, '?', encodings[fnum]);
672 }
673
674 if (last_fnum != fnum || no_spc) {
675 XSetFont(display, gc, fonts[last_fnum]->fid);
676 res = XTextExtents16(fonts[last_fnum], buf, i, &dir_ret, &fnt_asc, &fnt_dsc, &sizes);
677 /* recover the dimensions - should verify that res == 0 first! */
678 wd += sizes.width; /* accumulate the width */
679 hs = sizes.ascent + sizes.descent; /* total height */
680 if(hs > ht) ht = hs; /* new height exceeds previous height */
681 if(yt > (-sizes.ascent)) yt = -sizes.ascent; /* delta y offset */
682 i = 0;
683 (*buf).byte1 = glyph[0];
684 (*buf).byte2 = glyph[1];
685 if (no_spc) {
686 wd -= XTextWidth16(fonts[fnum], buf, 1);
687 }
688 } else {
689 (*(buf + i)).byte1 = glyph[0];
690 (*(buf + i)).byte2 = glyph[1];
691 }
692 last_fnum = fnum;
693 i++;
694 string += ulen;
695 num_bytes -= ulen;
696 }
697
698 XSetFont(display, gc, fonts[fnum]->fid);
699 res = XTextExtents16(fonts[fnum], buf, i, &dir_ret, &fnt_asc, &fnt_dsc, &sizes);
700 /* recover the dimensions - should verify that res == 0 first! */
701 wd += sizes.width; /* accumulate the width */
702 hs = sizes.ascent + sizes.descent; /* total height */
703 if(hs > ht) ht = hs; /* new height exceeds previous height */
704 if(yt > (-sizes.ascent)) yt = -sizes.ascent; /* delta y offset */
705 /* return values */
706 *ww = wd; /* width of inked area rectangle */
707 *hh = ht; /* max height of inked area rectangle */
708 *xx = 0; /* x-offset from origin to start of inked area - this is wrong! */
709 *yy = yt; /* y-offset from origin to start of inked rectangle */
710 }
711
712
713 /*****************************************************************************/
714 /** returns the pixel width of a UTF-8 string **/
715 /*****************************************************************************/
716 int
XUtf8TextWidth(XUtf8FontStruct * font_set,const char * string,int num_bytes)717 XUtf8TextWidth(XUtf8FontStruct *font_set,
718 const char *string,
719 int num_bytes) {
720
721 int x;
722 int *encodings; /* encodings array */
723 XFontStruct **fonts; /* fonts array */
724 Fl_XChar2b buf[128]; /* drawing buffer */
725 int fnum; /* index of the current font in the fonts array*/
726 int i; /* current byte in the XChar2b buffer */
727 int first; /* first valid font index */
728 int last_fnum; /* font index of the previous char */
729 int nb_font; /* quantity of fonts in the font array */
730 char glyph[2]; /* byte1 and byte2 value of the UTF-8 char */
731 int *ranges; /* sub range of iso10646 */
732
733 nb_font = font_set->nb_font;
734 x = 0;
735
736 if (nb_font < 1) {
737 /* there is no font in the font_set :-( */
738 return x;
739 }
740
741 ranges = font_set->ranges;
742 fonts = font_set->fonts;
743 encodings = font_set->encodings;
744 i = 0;
745 fnum = 0;
746
747 while(fnum < nb_font && !fonts[fnum]) fnum++;
748 if (fnum >= nb_font) {
749 /* there is no valid font for the X server */
750 return x;
751 }
752
753 first = fnum;
754 last_fnum = fnum;
755
756 while (num_bytes > 0) {
757 int ulen; /* byte length of the UTF-8 char */
758 unsigned int ucs; /* Unicode value of the UTF-8 char */
759 unsigned int no_spc; /* Spacing char equivalent of a non-spacing char */
760
761 if (i > 120) {
762 /*** measure the buffer **/
763 x += XTextWidth16(fonts[fnum], buf, i);
764 i = 0;
765 }
766
767 ulen = XFastConvertUtf8ToUcs((unsigned char*)string, num_bytes, &ucs);
768
769 if (ulen < 1) ulen = 1;
770
771 no_spc = XUtf8IsNonSpacing(ucs);
772 if (no_spc) {
773 ucs = no_spc;
774 }
775
776 /*
777 * find the first encoding which can be used to
778 * draw the glyph
779 */
780 fnum = first;
781 while (fnum < nb_font) {
782 if (fonts[fnum] && ucs2fontmap(glyph, ucs, encodings[fnum]) >= 0) {
783 if (encodings[fnum] != 0 ||
784 (ucs >= ranges[fnum * 2] &&
785 ucs <= ranges[fnum * 2 + 1])) {
786 break;
787 }
788 }
789 fnum++;
790 }
791 if (fnum == nb_font) {
792 /* the char is not valid in all encodings ->
793 * draw it using the first font :-(
794 */
795 fnum = first;
796 ucs2fontmap(glyph, '?', encodings[fnum]);
797 }
798
799 if (last_fnum != fnum || no_spc) {
800 x += XTextWidth16(fonts[last_fnum], buf, i);
801 i = 0;
802 (*buf).byte1 = glyph[0];
803 (*buf).byte2 = glyph[1];
804 if (no_spc) {
805 /* go back to draw the non-spacing char over the previous char */
806 x -= XTextWidth16(fonts[fnum], buf, 1);
807 }
808 } else {
809 (*(buf + i)).byte1 = glyph[0];
810 (*(buf + i)).byte2 = glyph[1];
811 }
812 last_fnum = fnum;
813 i++;
814 string += ulen;
815 num_bytes -= ulen;
816 }
817
818 x += XTextWidth16(fonts[last_fnum], buf, i);
819
820 return x;
821 }
822
823 /*****************************************************************************/
824 /** get the X font and glyph ID of a UCS char **/
825 /*****************************************************************************/
826 int
XGetUtf8FontAndGlyph(XUtf8FontStruct * font_set,unsigned int ucs,XFontStruct ** fnt,unsigned short * id)827 XGetUtf8FontAndGlyph(XUtf8FontStruct *font_set,
828 unsigned int ucs,
829 XFontStruct **fnt,
830 unsigned short *id) {
831
832 int x;
833 int *encodings; /* encodings array */
834 XFontStruct **fonts; /* fonts array */
835 int fnum; /* index of the current font in the fonts array*/
836 int i; /* current byte in the XChar2b buffer */
837 int first; /* first valid font index */
838 int last_fnum; /* font index of the previous char */
839 int nb_font; /* quantity of fonts in the font array */
840 char glyph[2]; /* byte1 and byte2 value of the UTF-8 char */
841 int *ranges; /* sub range of iso10646 */
842
843 nb_font = font_set->nb_font;
844 x = 0;
845
846 if (nb_font < 1) {
847 /* there is no font in the font_set :-( */
848 return -1;
849 }
850
851 ranges = font_set->ranges;
852 fonts = font_set->fonts;
853 encodings = font_set->encodings;
854 i = 0;
855 fnum = 0;
856
857 while(fnum < nb_font && !fonts[fnum]) fnum++;
858 if (fnum >= nb_font) {
859 /* there is no valid font for the X server */
860 return -1;
861 }
862
863 first = fnum;
864 last_fnum = fnum;
865
866 /*
867 * find the first encoding which can be used to
868 * draw the glyph
869 */
870 fnum = first;
871 while (fnum < nb_font) {
872 if (fonts[fnum] && ucs2fontmap(glyph, ucs, encodings[fnum]) >= 0) {
873 if (encodings[fnum] != 0 ||
874 (ucs >= ranges[fnum * 2] &&
875 ucs <= ranges[fnum * 2 + 1])) {
876 break;
877 }
878 }
879 fnum++;
880 }
881 if (fnum == nb_font) {
882 /* the char is not valid in all encodings ->
883 * draw it using the first font :-(
884 */
885 fnum = first;
886 ucs2fontmap(glyph, '?', encodings[fnum]);
887 }
888
889 *id = ((unsigned char)glyph[0] << 8) | (unsigned char)glyph[1] ;
890 *fnt = fonts[fnum];
891 return 0;
892 }
893
894 /*****************************************************************************/
895 /** returns the pixel width of a UCS char **/
896 /*****************************************************************************/
897 int
XUtf8UcsWidth(XUtf8FontStruct * font_set,unsigned int ucs)898 XUtf8UcsWidth(XUtf8FontStruct *font_set,
899 unsigned int ucs) {
900
901 int x;
902 int *encodings; /* encodings array */
903 XFontStruct **fonts; /* fonts array */
904 Fl_XChar2b buf[8]; /* drawing buffer */
905 int fnum; /* index of the current font in the fonts array*/
906 int i; /* current byte in the XChar2b buffer */
907 int first; /* first valid font index */
908 int last_fnum; /* font index of the previous char */
909 int nb_font; /* quantity of fonts in the font array */
910 char glyph[2]; /* byte1 and byte2 value of the UTF-8 char */
911 int *ranges; /* sub range of iso10646 */
912
913 nb_font = font_set->nb_font;
914 x = 0;
915
916 if (nb_font < 1) {
917 /* there is no font in the font_set :-( */
918 return x;
919 }
920
921 ranges = font_set->ranges;
922 fonts = font_set->fonts;
923 encodings = font_set->encodings;
924 i = 0;
925 fnum = 0;
926
927 while(fnum < nb_font && !fonts[fnum]) fnum++;
928 if (fnum >= nb_font) {
929 /* there is no valid font for the X server */
930 return x;
931 }
932
933 first = fnum;
934 last_fnum = fnum;
935
936 ucs = XUtf8IsNonSpacing(ucs);
937
938 /*
939 * find the first encoding which can be used to
940 * draw the glyph
941 */
942 fnum = first;
943 while (fnum < nb_font) {
944 if (fonts[fnum] &&
945 ucs2fontmap(glyph, ucs, encodings[fnum]) >= 0) {
946 if (encodings[fnum] != 0 || (ucs >= ranges[fnum * 2] &&
947 ucs <= ranges[fnum * 2 + 1])) {
948 break;
949 }
950 }
951 fnum++;
952 }
953 if (fnum == nb_font) {
954 /* the char is not valid in all encodings ->
955 * draw it using the first font :-(
956 */
957 fnum = first;
958 ucs2fontmap(glyph, '?', encodings[fnum]);
959 }
960
961 (*buf).byte1 = glyph[0];
962 (*buf).byte2 = glyph[1];
963
964 x += XTextWidth16(fonts[fnum], buf, 1);
965
966 return x;
967 }
968
969 /*****************************************************************************/
970 /** draw an UTF-8 string and clear the background. **/
971 /*****************************************************************************/
972 void
XUtf8DrawImageString(Display * display,Drawable d,XUtf8FontStruct * font_set,GC gc,int x,int y,const char * string,int num_bytes)973 XUtf8DrawImageString(Display *display,
974 Drawable d,
975 XUtf8FontStruct *font_set,
976 GC gc,
977 int x,
978 int y,
979 const char *string,
980 int num_bytes) {
981
982 /* FIXME: must be improved ! */
983 int w;
984 int fill_style;
985 unsigned long foreground;
986 unsigned long background;
987 int function;
988 XGCValues xgcv;
989
990 w = XUtf8TextWidth(font_set, string, num_bytes);
991
992 XGetGCValues(display, gc,
993 GCFunction|GCForeground|GCBackground|GCFillStyle, &xgcv);
994
995 function = xgcv.function;
996 fill_style = xgcv.fill_style;
997 foreground = xgcv.foreground;
998 background = xgcv.background;
999
1000 xgcv.function = GXcopy;
1001 xgcv.foreground = background;
1002 xgcv.background = foreground;
1003 xgcv.fill_style = FillSolid;
1004
1005 XChangeGC(display, gc,
1006 GCFunction|GCForeground|GCBackground|GCFillStyle, &xgcv);
1007
1008 XFillRectangle(display, d, gc, x, y - font_set->ascent,
1009 (unsigned)w, (unsigned)(font_set->ascent + font_set->descent));
1010
1011 xgcv.function = function;
1012 xgcv.foreground = foreground;
1013 xgcv.background = background;
1014 xgcv.fill_style = fill_style;
1015
1016 XChangeGC(display, gc,
1017 GCFunction|GCForeground|GCBackground|GCFillStyle, &xgcv);
1018
1019 XUtf8DrawString(display, d, font_set, gc, x, y, string, num_bytes);
1020 }
1021
1022 /*****************************************************************************/
1023 /** free the XFontSet and others things created by XCreateUtf8FontSet **/
1024 /*****************************************************************************/
1025 void
XFreeUtf8FontStruct(Display * dpy,XUtf8FontStruct * font_set)1026 XFreeUtf8FontStruct(Display *dpy,
1027 XUtf8FontStruct *font_set) {
1028
1029 int i;
1030 i = 0;
1031 while (i < font_set->nb_font) {
1032 if (font_set->fonts[i]) {
1033 XFreeFont(dpy, font_set->fonts[i]);
1034 free(font_set->font_name_list[i]);
1035 }
1036 i++;
1037 }
1038 free(font_set->ranges);
1039 free(font_set->font_name_list);
1040 free(font_set->fonts);
1041 free(font_set->encodings);
1042 free(font_set);
1043 }
1044
1045 #endif /* X11 only */
1046
1047 /*
1048 * End of "$Id: utf8Wrap.c 8401 2011-02-08 10:06:19Z ianmacarthur $".
1049 */
1050