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