fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
  SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation)  

utf8Wrap.c

Go to the documentation of this file.
00001 /* "$Id: $"
00002  *
00003  * Author: Jean-Marc Lienher ( http://oksid.ch )
00004  * Copyright 2000-2003 by O'ksi'D.
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Library General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Library General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Library General Public
00017  * License along with this library; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00019  * USA.
00020  *
00021  * Please report all bugs and problems on the following page:
00022  *
00023  *     http://www.fltk.org/str.php
00024  */
00025 
00026 /*
00027  * X11 UTF-8 text drawing functions.
00028  */
00029 #if !defined(WIN32) && !defined(__APPLE__)
00030 
00031 #include "../../FL/Xutf8.h"
00032 #include <X11/Xlib.h>
00033 #include <ctype.h>
00034 #include <stdlib.h>
00035 #include <string.h>
00036 #include <stdio.h>
00037 
00038 /* External auto generated functions : */
00039 #include "ucs2fontmap.c"
00040 /* 
00041  * extern int ucs2fontmap(char *s, unsigned int ucs, int enc);
00042  * extern int encoding_number(const char *enc);
00043  * extern const char *encoding_name(int num);
00044  */
00045 
00046 /* The ARM header files have a bug by not taking into account that ARM cpu
00047  * likes pacing to 4 bytes. This little trick defines our own version of
00048  * XChar2b which does not have this problem
00049  */
00050 
00051 #if defined(__GNUC__) && defined(__arm__) && !defined(__ARM_EABI__)
00052 typedef struct {
00053   unsigned char byte1;
00054   unsigned char byte2;
00055 }
00056 __attribute__ ((packed))
00057 Fl_XChar2b;
00058 #else
00059 #define Fl_XChar2b XChar2b
00060 #endif
00061 
00062 
00063 /*********************************************************************/
00065 /*********************************************************************/
00066 static int 
00067 get_font_list(
00068         const char      *base_font_name_list, 
00069         char            ***flist) {
00070   const char *ptr;
00071   const char *p;
00072   int nb;
00073   int nb_name;
00074   
00075   ptr = base_font_name_list;
00076   p = NULL;
00077   nb = 0;
00078   nb_name = 1;
00079 
00080   while (*ptr) {
00081     if (*ptr == ',') nb_name++;
00082     ptr++;
00083   }
00084 
00085   *flist = (char **) malloc(sizeof(char*) * nb_name);
00086   ptr = base_font_name_list;
00087 
00088   while (*ptr) {
00089     int l = 0, i = 0;
00090 
00091     while(isspace(*ptr)) ptr++;
00092     p = ptr;
00093     while (*ptr && *ptr != ',') { ptr++; l++; }
00094     if (l > 2) {
00095       (*flist)[nb] = (char*) malloc((unsigned)l + 2);
00096       while (p != ptr) { ((*flist)[nb])[i] = *p; i++; p++; }
00097       (*flist)[nb][i] = '\0';
00098       nb++;
00099     }
00100     if (*ptr) ptr++;
00101   }
00102   if (nb < 1) {
00103     free(*flist);
00104     *flist = (char**)NULL;
00105   }
00106   return nb;    
00107 }
00108 
00109 /*********************************************************************/
00112 /*********************************************************************/
00113 static int 
00114 font_spec_enc(char *font) {
00115   int ret;
00116   char *enc;
00117   char *end;
00118 
00119   enc = font;
00120   while (*enc != '-') enc++; 
00121   enc++;
00122   while (*enc != '-') enc++;
00123   enc++;
00124   end = enc;
00125   while (*end != '-') end++;
00126   *end = '\0';
00127   
00128   ret = encoding_number(enc);
00129   *end = '-';
00130 
00131   return ret;
00132 }
00133 
00134 
00135 /*********************************************************************/
00137 /*********************************************************************/
00138 static void
00139 get_range(const char    *enc,
00140           int           *min,
00141           int           *max) {
00142 
00143   const char *ptr = enc;
00144   const char *ptr1;
00145 
00146   if (!enc) return;
00147 
00148   while (*ptr && *ptr != '-') ptr++;
00149   if (!*ptr) return;
00150   while (*ptr && *ptr != '[') ptr++;
00151   if (!*ptr) return;
00152   *min = 0xFFFF;
00153   *max = 0;
00154   while (*ptr && *ptr != ']') {
00155     int val;
00156     ptr++;
00157     ptr1 = ptr;
00158     while (*ptr && *ptr != ']' && *ptr != ' ' && *ptr != '_') ptr++;
00159     val = strtol(ptr1, NULL, 0);
00160     if (val < *min) *min = val;
00161     if (val > *max) *max = val;
00162   }     
00163 }
00164 
00165 /*********************************************************************/
00167 /*********************************************************************/
00168 static int *
00169 get_encodings(char      **font_name_list, 
00170               int       *ranges,
00171               int       nb_font) {
00172 
00173   int *font_encoding_list;
00174   int i;
00175   i = 0;
00176 
00177   font_encoding_list = (int *) malloc(sizeof(int) * nb_font);
00178   while (i < nb_font) {
00179     char *ptr;
00180     int ec;
00181     ptr = font_name_list[i];
00182     ec = 0;
00183     font_encoding_list[i] = -1;
00184     ranges[i * 2] = 0;
00185     ranges[i * 2 + 1] = 0xFFFF;
00186     
00187     if (ptr && strstr(ptr, "fontspecific")) {
00188       font_encoding_list[i] = font_spec_enc(ptr);
00189       ptr = NULL;
00190     }
00191     while (ptr && *ptr) {
00192       if (*ptr == '-') {
00193         ec++;
00194         if (ec == 13) {
00195           font_encoding_list[i] = encoding_number(ptr + 1);
00196           if (font_encoding_list[i] == 0) {
00197             get_range(ptr + 1, 
00198                       ranges + i * 2,
00199                       ranges + i * 2 + 1);
00200           }
00201           break;
00202         }
00203       } 
00204       ptr++;
00205     }
00206     if (font_encoding_list[i] < 0) font_encoding_list[i] = 1;
00207     i++;
00208   }
00209   return font_encoding_list;
00210 }
00211 
00212 /*********************************************************************/
00214 /*********************************************************************/
00215 XFontStruct *
00216 find_best_font(Display  *dpy,
00217                char     **name) {
00218 
00219   char **list;
00220   int cnt;
00221   XFontStruct *s;
00222 
00223   list = XListFonts(dpy, *name, 1, &cnt);
00224   if (cnt && list) {
00225     free(*name);
00226     *name = strdup(list[0]);
00227     s = XLoadQueryFont(dpy, *name);
00228     XFreeFontNames(list);
00229     return s;
00230   }
00231   return NULL;
00232 }
00233 
00234 /*********************************************************************/
00236 /*********************************************************************/
00237 static void 
00238 load_fonts(Display         *dpy, 
00239            XUtf8FontStruct *font_set) {
00240 
00241   int i;
00242   char **list;
00243 
00244   i = 0;
00245   list = NULL;
00246 
00247   font_set->fonts = (XFontStruct**) malloc(sizeof(XFontStruct*) *
00248                                            font_set->nb_font);
00249   
00250   font_set->ranges = (int*) malloc(sizeof(int) * 
00251                                    font_set->nb_font * 2);
00252 
00253   font_set->descent = 0;
00254   font_set->ascent = 0;
00255   font_set->fid = 0;
00256 
00257   while (i < font_set->nb_font) {
00258     XFontStruct *fnt;
00259 
00260     fnt = font_set->fonts[i] = 
00261       find_best_font(dpy, &(font_set->font_name_list[i]));
00262     if (fnt) {
00263       font_set->fid = fnt->fid;
00264       if (fnt->ascent > font_set->ascent) {
00265         font_set->ascent = fnt->ascent;
00266       }
00267       if (fnt->descent > font_set->descent) {
00268         font_set->descent = fnt->descent;
00269       }
00270     } else {
00271       free(font_set->font_name_list[i]);
00272       font_set->font_name_list[i] = NULL;
00273     }
00274     i++;
00275   }
00276 
00277   font_set->encodings = 
00278     get_encodings(font_set->font_name_list, 
00279       font_set->ranges, font_set->nb_font);
00280 
00281   /* unload fonts with same encoding */
00282   for (i = 0; i < font_set->nb_font; i++) {
00283     if (font_set->font_name_list[i]) {
00284       int j;
00285       for (j = 0; j < i; j++) {
00286         if (font_set->font_name_list[j] &&
00287             font_set->encodings[j] ==
00288             font_set->encodings[i] &&
00289             font_set->ranges[2*j] ==
00290             font_set->ranges[2*i] &&
00291             font_set->ranges[(2*j)+1] &&
00292             font_set->ranges[(2*i)+1]) {
00293           XFreeFont(dpy, font_set->fonts[i]);
00294           free(font_set->font_name_list[i]);
00295           font_set->font_name_list[i] = NULL;
00296           font_set->fonts[i] = 0;
00297         }
00298       }
00299     }
00300   } 
00301 }
00302 
00303 /*********************************************************************/
00306 /*********************************************************************/
00307 XUtf8FontStruct *
00308 XCreateUtf8FontStruct(Display    *dpy,
00309                       const char *base_font_name_list) {
00310 
00311   XUtf8FontStruct *font_set;
00312   
00313   font_set = (XUtf8FontStruct*)malloc(sizeof(XUtf8FontStruct));
00314 
00315   if (!font_set) {
00316     return NULL;
00317   }
00318 
00319   font_set->nb_font = get_font_list(base_font_name_list, 
00320                                     &font_set->font_name_list);
00321 
00322   if (font_set->nb_font < 1) {
00323     free(font_set);
00324     return NULL;
00325   }
00326 
00327   load_fonts(dpy, font_set);
00328 
00329   return font_set;
00330 }
00331 
00332 
00333 /*****************************************************************************/
00335 /*****************************************************************************/
00336 void 
00337 XUtf8DrawRtlString(Display              *display, 
00338                    Drawable             d,
00339                    XUtf8FontStruct      *font_set, 
00340                    GC                   gc, 
00341                    int                  x, 
00342                    int                  y, 
00343                    const char           *string,
00344                    int                  num_bytes) {
00345 
00346   int           *encodings;     /* encodings array */
00347   XFontStruct   **fonts;        /* fonts array */
00348   Fl_XChar2b    buf[128];       /* drawing buffer */
00349   Fl_XChar2b    *ptr;           /* pointer to the drawing buffer */
00350   int           fnum;           /* index of the current font in the fonts array*/
00351   int           i;              /* current byte in the XChar2b buffer */
00352   int           first;          /* first valid font index */
00353   int           last_fnum;      /* font index of the previous char */
00354   int           nb_font;        /* quantity of fonts in the font array */
00355   char          glyph[2];       /* byte1 and byte1 value of the UTF-8 char */
00356   int           *ranges;        /* sub range of iso10646 */
00357 
00358   nb_font = font_set->nb_font;
00359 
00360   if (nb_font < 1) {
00361     /* there is no font in the font_set :-( */
00362     return;
00363   }
00364   
00365   ranges = font_set->ranges;
00366   fonts = font_set->fonts;
00367   encodings = font_set->encodings;
00368   i = 0;
00369   fnum = 0;
00370   ptr = buf + 128;
00371   
00372   while(fnum < nb_font && !fonts[fnum]) fnum++;
00373   if (fnum >= nb_font) {
00374     /* there is no valid font for the X server */
00375     return;
00376   }
00377 
00378   first = fnum;
00379   last_fnum = fnum;
00380 
00381   while (num_bytes > 0) {
00382     int          ulen;   /* byte length of the UTF-8 char */
00383     unsigned int ucs;    /* Unicode value of the UTF-8 char */
00384     unsigned int no_spc; /* Spacing char equivalent of a non-spacing char */
00385 
00386     if (i > 120) {
00387       /*** draw the buffer **/
00388       XSetFont(display, gc, fonts[fnum]->fid);
00389       x -= XTextWidth16(fonts[fnum], ptr, i);
00390       XDrawString16(display, d, gc, x, y, ptr, i);
00391       i = 0;
00392       ptr = buf + 128;
00393     }
00394 
00395     ulen = XFastConvertUtf8ToUcs((unsigned char*)string, num_bytes, &ucs); 
00396 
00397     if (ulen < 1) ulen = 1; 
00398 
00399     no_spc = XUtf8IsNonSpacing(ucs);
00400     if (no_spc) ucs = no_spc; 
00401 
00402     /* 
00403      * find the first encoding which can be used to     
00404      * draw the glyph                           
00405      */
00406     fnum = first;
00407     while (fnum < nb_font) {
00408       if (fonts[fnum] && ucs2fontmap(glyph, ucs, encodings[fnum]) >= 0) {
00409         if (encodings[fnum] != 0 || 
00410             (ucs >= ranges[fnum * 2] && ucs <= ranges[fnum * 2 + 1])) {
00411           break;
00412         }
00413       }
00414       fnum++;
00415     }
00416     if (fnum == nb_font) {
00417       /* the char is not valid in all encodings ->
00418        * draw it using the first font :-(
00419        */
00420       fnum = first;
00421       ucs2fontmap(glyph, '?', encodings[fnum]);
00422     }
00423 
00424     if (last_fnum != fnum || no_spc) {
00425       XSetFont(display, gc, fonts[last_fnum]->fid);
00426       x -= XTextWidth16(fonts[last_fnum], ptr, i);
00427       XDrawString16(display, d, gc, x, y, ptr, i);
00428       i = 0;
00429       ptr = buf + 127;
00430       (*ptr).byte1 = glyph[0];
00431       (*ptr).byte2 = glyph[1];
00432       if (no_spc) {
00433         x += XTextWidth16(fonts[fnum], ptr, 1);
00434       }
00435     } else {
00436       ptr--;
00437       (*ptr).byte1 = glyph[0];
00438       (*ptr).byte2 = glyph[1];
00439     }
00440     last_fnum = fnum;
00441     i++;
00442     string += ulen;
00443     num_bytes -= ulen;
00444   }
00445 
00446   if (i < 1) return;
00447 
00448   XSetFont(display, gc, fonts[fnum]->fid);
00449   x -= XTextWidth16(fonts[last_fnum], ptr, i);
00450   XDrawString16(display, d, gc, x, y, ptr, i);
00451 }
00452 
00453 
00454 /*****************************************************************************/
00456 /*****************************************************************************/
00457 void 
00458 XUtf8DrawString(Display         *display, 
00459                 Drawable        d,
00460                 XUtf8FontStruct *font_set, 
00461                 GC              gc, 
00462                 int             x, 
00463                 int             y, 
00464                 const char      *string,
00465                 int             num_bytes) {
00466 
00467   int           *encodings; /* encodings array */
00468   XFontStruct   **fonts;    /* fonts array */
00469   Fl_XChar2b    buf[128];   /* drawing buffer */
00470   int           fnum;       /* index of the current font in the fonts array*/
00471   int           i;          /* current byte in the XChar2b buffer */
00472   int           first;      /* first valid font index */
00473   int           last_fnum;  /* font index of the previous char */
00474   int           nb_font;    /* quantity of fonts in the font array */
00475   char          glyph[2];   /* byte1 and byte1 value of the UTF-8 char */
00476   int           *ranges;    /* sub range of iso10646 */
00477 
00478   nb_font = font_set->nb_font;
00479 
00480   if (nb_font < 1) {
00481     /* there is no font in the font_set :-( */
00482     return;
00483   }
00484   ranges = font_set->ranges;
00485   fonts = font_set->fonts;
00486   encodings = font_set->encodings;
00487   i = 0;
00488   fnum = 0;
00489   
00490   while(fnum < nb_font && !fonts[fnum]) fnum++;
00491   if (fnum >= nb_font) {
00492     /* there is no valid font for the X server */
00493     return;
00494   }
00495 
00496   first = fnum;
00497   last_fnum = fnum;
00498 
00499   while (num_bytes > 0) {
00500     int          ulen;   /* byte length of the UTF-8 char */
00501     unsigned int ucs;    /* Unicode value of the UTF-8 char */
00502     unsigned int no_spc; /* Spacing char equivalent of a non-spacing char */
00503 
00504     if (i > 120) {
00505       /*** draw the buffer **/
00506       XSetFont(display, gc, fonts[fnum]->fid);
00507       XDrawString16(display, d, gc, x, y, buf, i);
00508       x += XTextWidth16(fonts[fnum], buf, i);
00509       i = 0;
00510     }
00511 
00512     ulen = XFastConvertUtf8ToUcs((unsigned char*)string, num_bytes, &ucs); 
00513 
00514     if (ulen < 1) ulen = 1; 
00515 
00516     no_spc = XUtf8IsNonSpacing(ucs);
00517     if (no_spc) ucs = no_spc; 
00518 
00519     /* 
00520      * find the first encoding which can be used to     
00521      * draw the glyph                           
00522      */
00523     fnum = first;
00524     while (fnum < nb_font) {
00525       if (fonts[fnum] && ucs2fontmap(glyph, ucs, encodings[fnum]) >= 0) {
00526         if (encodings[fnum] != 0 || 
00527             (ucs >= ranges[fnum * 2] &&
00528             ucs <= ranges[fnum * 2 + 1])) {
00529           break;
00530         }
00531       }
00532       fnum++;
00533     }
00534     if (fnum == nb_font) {
00535       /* the char is not valid in all encodings ->
00536        * draw it using the first font :-(
00537        */
00538       fnum = first;
00539       ucs2fontmap(glyph, '?', encodings[fnum]);
00540     }
00541 
00542     if (last_fnum != fnum || no_spc) {
00543       XSetFont(display, gc, fonts[last_fnum]->fid);
00544       XDrawString16(display, d, gc, x, y, buf, i);
00545       x += XTextWidth16(fonts[last_fnum], buf, i);
00546       i = 0;
00547       (*buf).byte1 = glyph[0];
00548       (*buf).byte2 = glyph[1];
00549       if (no_spc) {
00550         x -= XTextWidth16(fonts[fnum], buf, 1);
00551       }
00552     } else {
00553       (*(buf + i)).byte1 = glyph[0];
00554       (*(buf + i)).byte2 = glyph[1];
00555     }
00556     last_fnum = fnum;
00557     i++;
00558     string += ulen;
00559     num_bytes -= ulen;
00560   }
00561 
00562   XSetFont(display, gc, fonts[fnum]->fid);
00563   XDrawString16(display, d, gc, x, y, buf, i);
00564 }
00565 
00566 
00567 
00568 /*****************************************************************************/
00570 /*****************************************************************************/
00571 int  
00572 XUtf8TextWidth(XUtf8FontStruct  *font_set, 
00573                const char       *string,
00574                int              num_bytes) {
00575 
00576   int           x;
00577   int           *encodings; /* encodings array */
00578   XFontStruct   **fonts;    /* fonts array */
00579   Fl_XChar2b    buf[128];   /* drawing buffer */
00580   int           fnum;       /* index of the current font in the fonts array*/
00581   int           i;          /* current byte in the XChar2b buffer */
00582   int           first;      /* first valid font index */
00583   int           last_fnum;  /* font index of the previous char */
00584   int           nb_font;    /* quantity of fonts in the font array */
00585   char          glyph[2];   /* byte1 and byte1 value of the UTF-8 char */
00586   int           *ranges;    /* sub range of iso10646 */
00587 
00588   nb_font = font_set->nb_font;
00589   x = 0;
00590 
00591   if (nb_font < 1) {
00592     /* there is no font in the font_set :-( */
00593     return x;
00594   }
00595 
00596   ranges = font_set->ranges;
00597   fonts = font_set->fonts;
00598   encodings = font_set->encodings;
00599   i = 0;
00600   fnum = 0;
00601   
00602   while(fnum < nb_font && !fonts[fnum]) fnum++;
00603   if (fnum >= nb_font) {
00604     /* there is no valid font for the X server */
00605     return x;
00606   }
00607 
00608   first = fnum;
00609   last_fnum = fnum;
00610 
00611   while (num_bytes > 0) {
00612     int          ulen;   /* byte length of the UTF-8 char */
00613     unsigned int ucs;    /* Unicode value of the UTF-8 char */
00614     unsigned int no_spc; /* Spacing char equivalent of a non-spacing char */
00615 
00616     if (i > 120) {
00617       /*** measure the buffer **/
00618       x += XTextWidth16(fonts[fnum], buf, i);
00619       i = 0;
00620     }
00621 
00622     ulen = XFastConvertUtf8ToUcs((unsigned char*)string, num_bytes, &ucs); 
00623 
00624     if (ulen < 1) ulen = 1; 
00625 
00626     no_spc = XUtf8IsNonSpacing(ucs);
00627     if (no_spc) {
00628       ucs = no_spc;
00629     }
00630 
00631     /* 
00632      * find the first encoding which can be used to     
00633      * draw the glyph                           
00634      */
00635     fnum = first;
00636     while (fnum < nb_font) {
00637       if (fonts[fnum] && ucs2fontmap(glyph, ucs, encodings[fnum]) >= 0) {
00638         if (encodings[fnum] != 0 || 
00639                 (ucs >= ranges[fnum * 2] &&
00640                 ucs <= ranges[fnum * 2 + 1])) {
00641           break;
00642         }
00643       }
00644       fnum++;
00645     }
00646     if (fnum == nb_font) {
00647       /* the char is not valid in all encodings ->
00648        * draw it using the first font :-(
00649        */
00650       fnum = first;
00651       ucs2fontmap(glyph, '?', encodings[fnum]);
00652     }
00653 
00654     if (last_fnum != fnum || no_spc) {
00655       x += XTextWidth16(fonts[last_fnum], buf, i);
00656       i = 0;
00657       (*buf).byte1 = glyph[0];
00658       (*buf).byte2 = glyph[1];
00659       if (no_spc) {
00660         /* go back to draw the non-spacing char over the previous char */
00661         x -= XTextWidth16(fonts[fnum], buf, 1);
00662       }
00663     } else {
00664       (*(buf + i)).byte1 = glyph[0];
00665       (*(buf + i)).byte2 = glyph[1];
00666     }
00667     last_fnum = fnum;
00668     i++;
00669     string += ulen;
00670     num_bytes -= ulen;
00671   }
00672 
00673   x += XTextWidth16(fonts[last_fnum], buf, i);
00674 
00675   return x;
00676 }
00677 
00678 /*****************************************************************************/
00680 /*****************************************************************************/
00681 int
00682 XGetUtf8FontAndGlyph(XUtf8FontStruct  *font_set,
00683                      unsigned int     ucs,
00684                      XFontStruct      **fnt,
00685                      unsigned short   *id) {
00686 
00687   int             x;
00688   int             *encodings; /* encodings array */
00689   XFontStruct     **fonts;    /* fonts array */
00690   int             fnum;       /* index of the current font in the fonts array*/
00691   int             i;          /* current byte in the XChar2b buffer */
00692   int             first;      /* first valid font index */
00693   int             last_fnum;  /* font index of the previous char */
00694   int             nb_font;    /* quantity of fonts in the font array */
00695   char            glyph[2];   /* byte1 and byte1 value of the UTF-8 char */
00696   int             *ranges;    /* sub range of iso10646 */
00697 
00698   nb_font = font_set->nb_font;
00699   x = 0;
00700 
00701   if (nb_font < 1) {
00702     /* there is no font in the font_set :-( */
00703     return -1;
00704   }
00705 
00706   ranges = font_set->ranges;
00707   fonts = font_set->fonts;
00708   encodings = font_set->encodings;
00709   i = 0;
00710   fnum = 0;
00711 
00712   while(fnum < nb_font && !fonts[fnum]) fnum++;
00713   if (fnum >= nb_font) {
00714     /* there is no valid font for the X server */
00715     return -1;
00716   }
00717 
00718   first = fnum;
00719   last_fnum = fnum;
00720 
00721   /* 
00722    * find the first encoding which can be used to         
00723    * draw the glyph                               
00724    */
00725   fnum = first;
00726   while (fnum < nb_font) {
00727     if (fonts[fnum] && ucs2fontmap(glyph, ucs, encodings[fnum]) >= 0) {
00728       if (encodings[fnum] != 0 || 
00729           (ucs >= ranges[fnum * 2] &&
00730           ucs <= ranges[fnum * 2 + 1])) {
00731         break;
00732       }
00733     }
00734     fnum++;
00735   }
00736   if (fnum == nb_font) {
00737     /* the char is not valid in all encodings ->
00738      * draw it using the first font :-(
00739      */
00740     fnum = first;
00741     ucs2fontmap(glyph, '?', encodings[fnum]);
00742   }
00743 
00744   *id = ((unsigned char)glyph[0] << 8) | (unsigned char)glyph[1] ;
00745   *fnt = fonts[fnum];
00746   return 0;
00747 }
00748 
00749 /*****************************************************************************/
00751 /*****************************************************************************/
00752 int
00753 XUtf8UcsWidth(XUtf8FontStruct  *font_set,
00754               unsigned int     ucs) {
00755 
00756   int           x;
00757   int           *encodings; /* encodings array */
00758   XFontStruct   **fonts;    /* fonts array */
00759   Fl_XChar2b    buf[8];     /* drawing buffer */
00760   int           fnum;       /* index of the current font in the fonts array*/
00761   int           i;          /* current byte in the XChar2b buffer */
00762   int           first;      /* first valid font index */
00763   int           last_fnum;  /* font index of the previous char */
00764   int           nb_font;    /* quantity of fonts in the font array */
00765   char          glyph[2];   /* byte1 and byte1 value of the UTF-8 char */
00766   int           *ranges;    /* sub range of iso10646 */
00767 
00768   nb_font = font_set->nb_font;
00769   x = 0;
00770 
00771   if (nb_font < 1) {
00772     /* there is no font in the font_set :-( */
00773     return x;
00774   }
00775 
00776   ranges = font_set->ranges;
00777   fonts = font_set->fonts;
00778   encodings = font_set->encodings;
00779   i = 0;
00780   fnum = 0;
00781   
00782   while(fnum < nb_font && !fonts[fnum]) fnum++;
00783   if (fnum >= nb_font) {
00784     /* there is no valid font for the X server */
00785     return x;
00786   }
00787 
00788   first = fnum;
00789   last_fnum = fnum;
00790 
00791   ucs = XUtf8IsNonSpacing(ucs);
00792 
00793   /* 
00794    * find the first encoding which can be used to       
00795    * draw the glyph                             
00796    */
00797   fnum = first;
00798   while (fnum < nb_font) {
00799     if (fonts[fnum] && 
00800         ucs2fontmap(glyph, ucs, encodings[fnum]) >= 0) {
00801       if (encodings[fnum] != 0 || (ucs >= ranges[fnum * 2] &&
00802           ucs <= ranges[fnum * 2 + 1])) {
00803         break;
00804       }
00805     }
00806     fnum++;
00807   }
00808   if (fnum == nb_font) {
00809     /* the char is not valid in all encodings ->
00810      * draw it using the first font :-(
00811      */
00812     fnum = first;
00813     ucs2fontmap(glyph, '?', encodings[fnum]);
00814   }
00815 
00816   (*buf).byte1 = glyph[0];
00817   (*buf).byte2 = glyph[1];
00818 
00819   x += XTextWidth16(fonts[fnum], buf, 1);
00820 
00821   return x;
00822 }
00823 
00824 /*****************************************************************************/
00826 /*****************************************************************************/
00827 void
00828 XUtf8DrawImageString(Display         *display,
00829                      Drawable        d,
00830                      XUtf8FontStruct *font_set,
00831                      GC              gc,
00832                      int             x,
00833                      int             y,
00834                      const char      *string,
00835                      int             num_bytes) {
00836 
00837   /* FIXME: must be improved ! */
00838   int w;
00839   int fill_style;
00840   unsigned long foreground;
00841   unsigned long background;
00842   int function;
00843   XGCValues xgcv;
00844 
00845   w = XUtf8TextWidth(font_set, string, num_bytes);
00846   
00847   XGetGCValues(display, gc, 
00848                GCFunction|GCForeground|GCBackground|GCFillStyle, &xgcv);
00849   
00850   function = xgcv.function;
00851   fill_style = xgcv.fill_style;
00852   foreground = xgcv.foreground;
00853   background = xgcv.background;
00854 
00855   xgcv.function = GXcopy;
00856   xgcv.foreground = background;
00857   xgcv.background = foreground;
00858   xgcv.fill_style = FillSolid;
00859 
00860   XChangeGC(display, gc,
00861             GCFunction|GCForeground|GCBackground|GCFillStyle, &xgcv);
00862 
00863   XFillRectangle(display, d, gc, x, y - font_set->ascent, 
00864                  (unsigned)w, (unsigned)(font_set->ascent + font_set->descent));
00865 
00866   xgcv.function = function;
00867   xgcv.foreground = foreground;
00868   xgcv.background = background;
00869   xgcv.fill_style = fill_style;
00870 
00871   XChangeGC(display, gc,
00872             GCFunction|GCForeground|GCBackground|GCFillStyle, &xgcv);
00873 
00874   XUtf8DrawString(display, d, font_set, gc, x, y, string, num_bytes);
00875 }
00876 
00877 /*****************************************************************************/
00879 /*****************************************************************************/
00880 void 
00881 XFreeUtf8FontStruct(Display         *dpy, 
00882                     XUtf8FontStruct *font_set) {
00883 
00884   int i;
00885   i = 0;
00886   while (i < font_set->nb_font) {
00887     if (font_set->fonts[i]) {
00888         XFreeFont(dpy, font_set->fonts[i]);
00889         free(font_set->font_name_list[i]);
00890     }
00891     i++;
00892   }
00893   free(font_set->ranges);
00894   free(font_set->font_name_list);
00895   free(font_set->fonts);
00896   free(font_set->encodings);
00897   free(font_set);
00898 }
00899 
00900 #endif /* X11 only */
00901 
00902 /*
00903  *  End of "$Id: $".
00904  */