| /* "$Id: utf8Wrap.c 8401 2011-02-08 10:06:19Z ianmacarthur $" |
| * |
| * Author: Jean-Marc Lienher ( http://oksid.ch ) |
| * Copyright 2000-2003 by O'ksi'D. |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
| * USA. |
| * |
| * Please report all bugs and problems on the following page: |
| * |
| * http://www.fltk.org/str.php |
| */ |
| |
| /* |
| * X11 UTF-8 text drawing functions. |
| */ |
| #if !defined(WIN32) && !defined(__APPLE__) |
| |
| #include "../../FL/Xutf8.h" |
| #include <X11/Xlib.h> |
| #include <ctype.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <stdio.h> |
| |
| /* External auto generated functions : */ |
| #include "ucs2fontmap.c" |
| /* |
| * extern int ucs2fontmap(char *s, unsigned int ucs, int enc); |
| * extern int encoding_number(const char *enc); |
| * extern const char *encoding_name(int num); |
| */ |
| |
| /* The ARM header files have a bug by not taking into account that ARM cpu |
| * likes pacing to 4 bytes. This little trick defines our own version of |
| * XChar2b which does not have this problem |
| */ |
| |
| #if defined(__GNUC__) && defined(__arm__) && !defined(__ARM_EABI__) |
| typedef struct { |
| unsigned char byte1; |
| unsigned char byte2; |
| } |
| __attribute__ ((packed)) |
| Fl_XChar2b; |
| #else |
| #define Fl_XChar2b XChar2b |
| #endif |
| |
| |
| /*********************************************************************/ |
| /** extract a list of font from the base font name list **/ |
| /*********************************************************************/ |
| static int |
| get_font_list( |
| const char *base_font_name_list, |
| char ***flist) { |
| const char *ptr; |
| const char *p; |
| int nb; |
| int nb_name; |
| |
| ptr = base_font_name_list; |
| p = NULL; |
| nb = 0; |
| nb_name = 1; |
| |
| while (*ptr) { |
| if (*ptr == ',') nb_name++; |
| ptr++; |
| } |
| |
| *flist = (char **) malloc(sizeof(char*) * nb_name); |
| ptr = base_font_name_list; |
| |
| while (*ptr) { |
| int l = 0, i = 0; |
| |
| while(isspace(*ptr)) ptr++; |
| p = ptr; |
| while (*ptr && *ptr != ',') { ptr++; l++; } |
| if (l > 2) { |
| (*flist)[nb] = (char*) malloc((unsigned)l + 2); |
| while (p != ptr) { ((*flist)[nb])[i] = *p; i++; p++; } |
| (*flist)[nb][i] = '\0'; |
| nb++; |
| } |
| if (*ptr) ptr++; |
| } |
| if (nb < 1) { |
| free(*flist); |
| *flist = (char**)NULL; |
| } |
| return nb; |
| } |
| |
| /*********************************************************************/ |
| /** get the font name used as encoding for "fontspecific" encoding **/ |
| /** (mainly used for adobe-symbol and adobe-zapfdingbats) **/ |
| /*********************************************************************/ |
| static int |
| font_spec_enc(char *font) { |
| int ret; |
| char *enc; |
| char *end; |
| |
| enc = font; |
| while (*enc != '-') enc++; |
| enc++; |
| while (*enc != '-') enc++; |
| enc++; |
| end = enc; |
| while (*end != '-') end++; |
| *end = '\0'; |
| |
| ret = encoding_number(enc); |
| *end = '-'; |
| |
| return ret; |
| } |
| |
| |
| /*********************************************************************/ |
| /** get the sub range of a iso10646-1 font **/ |
| /*********************************************************************/ |
| static void |
| get_range(const char *enc, |
| int *min, |
| int *max) { |
| |
| const char *ptr = enc; |
| const char *ptr1; |
| |
| if (!enc) return; |
| |
| while (*ptr && *ptr != '-') ptr++; |
| if (!*ptr) return; |
| while (*ptr && *ptr != '[') ptr++; |
| if (!*ptr) return; |
| *min = 0xFFFF; |
| *max = 0; |
| while (*ptr && *ptr != ']') { |
| int val; |
| ptr++; |
| ptr1 = ptr; |
| while (*ptr && *ptr != ']' && *ptr != ' ' && *ptr != '_') ptr++; |
| val = strtol(ptr1, NULL, 0); |
| if (val < *min) *min = val; |
| if (val > *max) *max = val; |
| } |
| } |
| |
| /*********************************************************************/ |
| /** get the internal encoding number of each fonts **/ |
| /*********************************************************************/ |
| static int * |
| get_encodings(char **font_name_list, |
| int *ranges, |
| int nb_font) { |
| |
| int *font_encoding_list; |
| int i; |
| i = 0; |
| |
| font_encoding_list = (int *) malloc(sizeof(int) * nb_font); |
| while (i < nb_font) { |
| char *ptr; |
| int ec; |
| ptr = font_name_list[i]; |
| ec = 0; |
| font_encoding_list[i] = -1; |
| ranges[i * 2] = 0; |
| ranges[i * 2 + 1] = 0xFFFF; |
| |
| if (ptr && strstr(ptr, "fontspecific")) { |
| font_encoding_list[i] = font_spec_enc(ptr); |
| ptr = NULL; |
| } |
| while (ptr && *ptr) { |
| if (*ptr == '-') { |
| ec++; |
| if (ec == 13) { |
| font_encoding_list[i] = encoding_number(ptr + 1); |
| if (font_encoding_list[i] == 0) { |
| get_range(ptr + 1, |
| ranges + i * 2, |
| ranges + i * 2 + 1); |
| } |
| break; |
| } |
| } |
| ptr++; |
| } |
| if (font_encoding_list[i] < 0) font_encoding_list[i] = 1; |
| i++; |
| } |
| return font_encoding_list; |
| } |
| |
| /*********************************************************************/ |
| /** find the first font which matches the name and load it. **/ |
| /*********************************************************************/ |
| XFontStruct * |
| find_best_font(Display *dpy, |
| char **name) { |
| |
| char **list; |
| int cnt; |
| XFontStruct *s; |
| |
| list = XListFonts(dpy, *name, 1, &cnt); |
| if (cnt && list) { |
| free(*name); |
| *name = strdup(list[0]); |
| s = XLoadQueryFont(dpy, *name); |
| XFreeFontNames(list); |
| return s; |
| } |
| return NULL; |
| } |
| |
| /*********************************************************************/ |
| /** load all fonts **/ |
| /*********************************************************************/ |
| static void |
| load_fonts(Display *dpy, |
| XUtf8FontStruct *font_set) { |
| |
| int i; |
| char **list; |
| |
| i = 0; |
| list = NULL; |
| |
| font_set->fonts = (XFontStruct**) malloc(sizeof(XFontStruct*) * |
| font_set->nb_font); |
| |
| font_set->ranges = (int*) malloc(sizeof(int) * |
| font_set->nb_font * 2); |
| |
| font_set->descent = 0; |
| font_set->ascent = 0; |
| font_set->fid = 0; |
| |
| while (i < font_set->nb_font) { |
| XFontStruct *fnt; |
| |
| fnt = font_set->fonts[i] = |
| find_best_font(dpy, &(font_set->font_name_list[i])); |
| if (fnt) { |
| font_set->fid = fnt->fid; |
| if (fnt->ascent > font_set->ascent) { |
| font_set->ascent = fnt->ascent; |
| } |
| if (fnt->descent > font_set->descent) { |
| font_set->descent = fnt->descent; |
| } |
| } else { |
| free(font_set->font_name_list[i]); |
| font_set->font_name_list[i] = NULL; |
| } |
| i++; |
| } |
| |
| font_set->encodings = |
| get_encodings(font_set->font_name_list, |
| font_set->ranges, font_set->nb_font); |
| |
| /* unload fonts with same encoding */ |
| for (i = 0; i < font_set->nb_font; i++) { |
| if (font_set->font_name_list[i]) { |
| int j; |
| for (j = 0; j < i; j++) { |
| if (font_set->font_name_list[j] && |
| font_set->encodings[j] == |
| font_set->encodings[i] && |
| font_set->ranges[2*j] == |
| font_set->ranges[2*i] && |
| font_set->ranges[(2*j)+1] && |
| font_set->ranges[(2*i)+1]) { |
| XFreeFont(dpy, font_set->fonts[i]); |
| free(font_set->font_name_list[i]); |
| font_set->font_name_list[i] = NULL; |
| font_set->fonts[i] = 0; |
| } |
| } |
| } |
| } |
| } |
| |
| /*********************************************************************/ |
| /** Creates an array of XFontStruct acording to the comma separated **/ |
| /** list of fonts. XLoad all fonts. **/ |
| /*********************************************************************/ |
| XUtf8FontStruct * |
| XCreateUtf8FontStruct(Display *dpy, |
| const char *base_font_name_list) { |
| |
| XUtf8FontStruct *font_set; |
| |
| font_set = (XUtf8FontStruct*)malloc(sizeof(XUtf8FontStruct)); |
| |
| if (!font_set) { |
| return NULL; |
| } |
| |
| font_set->nb_font = get_font_list(base_font_name_list, |
| &font_set->font_name_list); |
| |
| if (font_set->nb_font < 1) { |
| free(font_set); |
| return NULL; |
| } |
| |
| load_fonts(dpy, font_set); |
| |
| return font_set; |
| } |
| |
| |
| /*****************************************************************************/ |
| /** draw a Right To Left UTF-8 string using multiple fonts as needed. **/ |
| /*****************************************************************************/ |
| void |
| XUtf8DrawRtlString(Display *display, |
| Drawable d, |
| XUtf8FontStruct *font_set, |
| GC gc, |
| int x, |
| int y, |
| const char *string, |
| int num_bytes) { |
| |
| int *encodings; /* encodings array */ |
| XFontStruct **fonts; /* fonts array */ |
| Fl_XChar2b buf[128]; /* drawing buffer */ |
| Fl_XChar2b *ptr; /* pointer to the drawing buffer */ |
| int fnum; /* index of the current font in the fonts array*/ |
| int i; /* current byte in the XChar2b buffer */ |
| int first; /* first valid font index */ |
| int last_fnum; /* font index of the previous char */ |
| int nb_font; /* quantity of fonts in the font array */ |
| char glyph[2]; /* byte1 and byte2 value of the UTF-8 char */ |
| int *ranges; /* sub range of iso10646 */ |
| |
| nb_font = font_set->nb_font; |
| |
| if (nb_font < 1) { |
| /* there is no font in the font_set :-( */ |
| return; |
| } |
| |
| ranges = font_set->ranges; |
| fonts = font_set->fonts; |
| encodings = font_set->encodings; |
| i = 0; |
| fnum = 0; |
| ptr = buf + 128; |
| |
| while(fnum < nb_font && !fonts[fnum]) fnum++; |
| if (fnum >= nb_font) { |
| /* there is no valid font for the X server */ |
| return; |
| } |
| |
| first = fnum; |
| last_fnum = fnum; |
| |
| while (num_bytes > 0) { |
| int ulen; /* byte length of the UTF-8 char */ |
| unsigned int ucs; /* Unicode value of the UTF-8 char */ |
| unsigned int no_spc; /* Spacing char equivalent of a non-spacing char */ |
| |
| if (i > 120) { |
| /*** draw the buffer **/ |
| XSetFont(display, gc, fonts[fnum]->fid); |
| x -= XTextWidth16(fonts[fnum], ptr, i); |
| XDrawString16(display, d, gc, x, y, ptr, i); |
| i = 0; |
| ptr = buf + 128; |
| } |
| |
| ulen = XFastConvertUtf8ToUcs((unsigned char*)string, num_bytes, &ucs); |
| |
| if (ulen < 1) ulen = 1; |
| |
| no_spc = XUtf8IsNonSpacing(ucs); |
| if (no_spc) ucs = no_spc; |
| |
| /* |
| * find the first encoding which can be used to |
| * draw the glyph |
| */ |
| fnum = first; |
| while (fnum < nb_font) { |
| if (fonts[fnum] && ucs2fontmap(glyph, ucs, encodings[fnum]) >= 0) { |
| if (encodings[fnum] != 0 || |
| (ucs >= ranges[fnum * 2] && ucs <= ranges[fnum * 2 + 1])) { |
| break; |
| } |
| } |
| fnum++; |
| } |
| if (fnum == nb_font) { |
| /* the char is not valid in all encodings -> |
| * draw it using the first font :-( |
| */ |
| fnum = first; |
| ucs2fontmap(glyph, '?', encodings[fnum]); |
| } |
| |
| if (last_fnum != fnum || no_spc) { |
| XSetFont(display, gc, fonts[last_fnum]->fid); |
| x -= XTextWidth16(fonts[last_fnum], ptr, i); |
| XDrawString16(display, d, gc, x, y, ptr, i); |
| i = 0; |
| ptr = buf + 127; |
| (*ptr).byte1 = glyph[0]; |
| (*ptr).byte2 = glyph[1]; |
| if (no_spc) { |
| x += XTextWidth16(fonts[fnum], ptr, 1); |
| } |
| } else { |
| ptr--; |
| (*ptr).byte1 = glyph[0]; |
| (*ptr).byte2 = glyph[1]; |
| } |
| last_fnum = fnum; |
| i++; |
| string += ulen; |
| num_bytes -= ulen; |
| } |
| |
| if (i < 1) return; |
| |
| XSetFont(display, gc, fonts[fnum]->fid); |
| x -= XTextWidth16(fonts[last_fnum], ptr, i); |
| XDrawString16(display, d, gc, x, y, ptr, i); |
| } |
| |
| |
| /*****************************************************************************/ |
| /** draw an UTF-8 string using multiple fonts as needed. **/ |
| /*****************************************************************************/ |
| void |
| XUtf8DrawString(Display *display, |
| Drawable d, |
| XUtf8FontStruct *font_set, |
| GC gc, |
| int x, |
| int y, |
| const char *string, |
| int num_bytes) { |
| |
| int *encodings; /* encodings array */ |
| XFontStruct **fonts; /* fonts array */ |
| Fl_XChar2b buf[128]; /* drawing buffer */ |
| int fnum; /* index of the current font in the fonts array*/ |
| int i; /* current byte in the XChar2b buffer */ |
| int first; /* first valid font index */ |
| int last_fnum; /* font index of the previous char */ |
| int nb_font; /* quantity of fonts in the font array */ |
| char glyph[2]; /* byte1 and byte2 value of the UTF-8 char */ |
| int *ranges; /* sub range of iso10646 */ |
| |
| nb_font = font_set->nb_font; |
| |
| if (nb_font < 1) { |
| /* there is no font in the font_set :-( */ |
| return; |
| } |
| ranges = font_set->ranges; |
| fonts = font_set->fonts; |
| encodings = font_set->encodings; |
| i = 0; |
| fnum = 0; |
| |
| while(fnum < nb_font && !fonts[fnum]) fnum++; |
| if (fnum >= nb_font) { |
| /* there is no valid font for the X server */ |
| return; |
| } |
| |
| first = fnum; |
| last_fnum = fnum; |
| |
| while (num_bytes > 0) { |
| int ulen; /* byte length of the UTF-8 char */ |
| unsigned int ucs; /* Unicode value of the UTF-8 char */ |
| unsigned int no_spc; /* Spacing char equivalent of a non-spacing char */ |
| |
| if (i > 120) { |
| /*** draw the buffer **/ |
| XSetFont(display, gc, fonts[fnum]->fid); |
| XDrawString16(display, d, gc, x, y, buf, i); |
| x += XTextWidth16(fonts[fnum], buf, i); |
| i = 0; |
| } |
| |
| ulen = XFastConvertUtf8ToUcs((unsigned char*)string, num_bytes, &ucs); |
| |
| if (ulen < 1) ulen = 1; |
| |
| no_spc = XUtf8IsNonSpacing(ucs); |
| if (no_spc) ucs = no_spc; |
| |
| /* |
| * find the first encoding which can be used to |
| * draw the glyph |
| */ |
| fnum = first; |
| while (fnum < nb_font) { |
| if (fonts[fnum] && ucs2fontmap(glyph, ucs, encodings[fnum]) >= 0) { |
| if (encodings[fnum] != 0 || |
| (ucs >= ranges[fnum * 2] && |
| ucs <= ranges[fnum * 2 + 1])) { |
| break; |
| } |
| } |
| fnum++; |
| } |
| if (fnum == nb_font) { |
| /* the char is not valid in all encodings -> |
| * draw it using the first font :-( |
| */ |
| fnum = first; |
| ucs2fontmap(glyph, '?', encodings[fnum]); |
| } |
| |
| if (last_fnum != fnum || no_spc) { |
| XSetFont(display, gc, fonts[last_fnum]->fid); |
| XDrawString16(display, d, gc, x, y, buf, i); |
| x += XTextWidth16(fonts[last_fnum], buf, i); |
| i = 0; |
| (*buf).byte1 = glyph[0]; |
| (*buf).byte2 = glyph[1]; |
| if (no_spc) { |
| x -= XTextWidth16(fonts[fnum], buf, 1); |
| } |
| } else { |
| (*(buf + i)).byte1 = glyph[0]; |
| (*(buf + i)).byte2 = glyph[1]; |
| } |
| last_fnum = fnum; |
| i++; |
| string += ulen; |
| num_bytes -= ulen; |
| } |
| |
| XSetFont(display, gc, fonts[fnum]->fid); |
| XDrawString16(display, d, gc, x, y, buf, i); |
| } |
| |
| |
| /*****************************************************************************/ |
| /** Measure the inked extents of a UTF-8 string using multiple fonts as **/ |
| /** needed. Tries to mirror the behaviour of the draw function **/ |
| /** XUtf8DrawString() as closely as possible to get consistent sizes. **/ |
| /*****************************************************************************/ |
| void |
| XUtf8_measure_extents( |
| Display *display, |
| Drawable d, |
| XUtf8FontStruct *font_set, |
| GC gc, |
| int *xx, /* x-offset from origin */ |
| int *yy, /* y-offset from origin */ |
| int *ww, /* overall inked width */ |
| int *hh, /* maximum inked height */ |
| const char *string, /* text to measure */ |
| int num_bytes) { |
| int *encodings; /* encodings array */ |
| XFontStruct **fonts; /* fonts array */ |
| Fl_XChar2b buf[128]; /* drawing buffer */ |
| int fnum; /* index of the current font in the fonts array*/ |
| int i; /* current byte in the XChar2b buffer */ |
| int first; /* first valid font index */ |
| int last_fnum; /* font index of the previous char */ |
| int nb_font; /* quantity of fonts in the font array */ |
| char glyph[2]; /* byte1 and byte2 value of the UTF-8 char */ |
| int *ranges; /* sub range of iso10646 */ |
| |
| int wd = 0; /* accumulates the width of the text */ |
| int ht = 0; /* used to find max height in text */ |
| int hs; /* "height sum" of current text segment */ |
| int yt = 0x7FFFFFFF; /* used to find bounding rectangle delta-y */ |
| int res; /* result from calling XTextExtents16() - we should test this is OK! */ |
| |
| XCharStruct sizes; |
| int dir_ret = 0; |
| int fnt_asc = 0; |
| int fnt_dsc = 0; |
| |
| nb_font = font_set->nb_font; |
| |
| if (nb_font < 1) { |
| /* there is no font in the font_set :-( */ |
| return; |
| } |
| ranges = font_set->ranges; |
| fonts = font_set->fonts; |
| encodings = font_set->encodings; |
| i = 0; |
| fnum = 0; |
| |
| while(fnum < nb_font && !fonts[fnum]) fnum++; |
| if (fnum >= nb_font) { |
| /* there is no valid font for the X server */ |
| return; |
| } |
| |
| first = fnum; |
| last_fnum = fnum; |
| |
| while (num_bytes > 0) { |
| int ulen; /* byte length of the UTF-8 char */ |
| unsigned int ucs; /* Unicode value of the UTF-8 char */ |
| unsigned int no_spc; /* Spacing char equivalent of a non-spacing char */ |
| |
| if (i > 120) { |
| /*** draw the buffer **/ |
| XSetFont(display, gc, fonts[fnum]->fid); |
| res = XTextExtents16(fonts[fnum], buf, i, &dir_ret, &fnt_asc, &fnt_dsc, &sizes); |
| /* recover the dimensions - should verify that res == 0 first! */ |
| wd += sizes.width; /* accumulate the width */ |
| hs = sizes.ascent + sizes.descent; /* total height */ |
| if(hs > ht) ht = hs; /* new height exceeds previous height */ |
| if(yt > (-sizes.ascent)) yt = -sizes.ascent; /* delta y offset */ |
| i = 0; |
| } |
| |
| ulen = XFastConvertUtf8ToUcs((unsigned char*)string, num_bytes, &ucs); |
| |
| if (ulen < 1) ulen = 1; |
| |
| no_spc = XUtf8IsNonSpacing(ucs); |
| if (no_spc) ucs = no_spc; |
| |
| /* |
| * find the first encoding which can be used to |
| * draw the glyph |
| */ |
| fnum = first; |
| while (fnum < nb_font) { |
| if (fonts[fnum] && ucs2fontmap(glyph, ucs, encodings[fnum]) >= 0) { |
| if (encodings[fnum] != 0 || |
| (ucs >= ranges[fnum * 2] && |
| ucs <= ranges[fnum * 2 + 1])) { |
| break; |
| } |
| } |
| fnum++; |
| } |
| if (fnum == nb_font) { |
| /* the char is not valid in all encodings -> |
| * draw it using the first font :-( |
| */ |
| fnum = first; |
| ucs2fontmap(glyph, '?', encodings[fnum]); |
| } |
| |
| if (last_fnum != fnum || no_spc) { |
| XSetFont(display, gc, fonts[last_fnum]->fid); |
| res = XTextExtents16(fonts[last_fnum], buf, i, &dir_ret, &fnt_asc, &fnt_dsc, &sizes); |
| /* recover the dimensions - should verify that res == 0 first! */ |
| wd += sizes.width; /* accumulate the width */ |
| hs = sizes.ascent + sizes.descent; /* total height */ |
| if(hs > ht) ht = hs; /* new height exceeds previous height */ |
| if(yt > (-sizes.ascent)) yt = -sizes.ascent; /* delta y offset */ |
| i = 0; |
| (*buf).byte1 = glyph[0]; |
| (*buf).byte2 = glyph[1]; |
| if (no_spc) { |
| wd -= XTextWidth16(fonts[fnum], buf, 1); |
| } |
| } else { |
| (*(buf + i)).byte1 = glyph[0]; |
| (*(buf + i)).byte2 = glyph[1]; |
| } |
| last_fnum = fnum; |
| i++; |
| string += ulen; |
| num_bytes -= ulen; |
| } |
| |
| XSetFont(display, gc, fonts[fnum]->fid); |
| res = XTextExtents16(fonts[fnum], buf, i, &dir_ret, &fnt_asc, &fnt_dsc, &sizes); |
| /* recover the dimensions - should verify that res == 0 first! */ |
| wd += sizes.width; /* accumulate the width */ |
| hs = sizes.ascent + sizes.descent; /* total height */ |
| if(hs > ht) ht = hs; /* new height exceeds previous height */ |
| if(yt > (-sizes.ascent)) yt = -sizes.ascent; /* delta y offset */ |
| /* return values */ |
| *ww = wd; /* width of inked area rectangle */ |
| *hh = ht; /* max height of inked area rectangle */ |
| *xx = 0; /* x-offset from origin to start of inked area - this is wrong! */ |
| *yy = yt; /* y-offset from origin to start of inked rectangle */ |
| } |
| |
| |
| /*****************************************************************************/ |
| /** returns the pixel width of a UTF-8 string **/ |
| /*****************************************************************************/ |
| int |
| XUtf8TextWidth(XUtf8FontStruct *font_set, |
| const char *string, |
| int num_bytes) { |
| |
| int x; |
| int *encodings; /* encodings array */ |
| XFontStruct **fonts; /* fonts array */ |
| Fl_XChar2b buf[128]; /* drawing buffer */ |
| int fnum; /* index of the current font in the fonts array*/ |
| int i; /* current byte in the XChar2b buffer */ |
| int first; /* first valid font index */ |
| int last_fnum; /* font index of the previous char */ |
| int nb_font; /* quantity of fonts in the font array */ |
| char glyph[2]; /* byte1 and byte2 value of the UTF-8 char */ |
| int *ranges; /* sub range of iso10646 */ |
| |
| nb_font = font_set->nb_font; |
| x = 0; |
| |
| if (nb_font < 1) { |
| /* there is no font in the font_set :-( */ |
| return x; |
| } |
| |
| ranges = font_set->ranges; |
| fonts = font_set->fonts; |
| encodings = font_set->encodings; |
| i = 0; |
| fnum = 0; |
| |
| while(fnum < nb_font && !fonts[fnum]) fnum++; |
| if (fnum >= nb_font) { |
| /* there is no valid font for the X server */ |
| return x; |
| } |
| |
| first = fnum; |
| last_fnum = fnum; |
| |
| while (num_bytes > 0) { |
| int ulen; /* byte length of the UTF-8 char */ |
| unsigned int ucs; /* Unicode value of the UTF-8 char */ |
| unsigned int no_spc; /* Spacing char equivalent of a non-spacing char */ |
| |
| if (i > 120) { |
| /*** measure the buffer **/ |
| x += XTextWidth16(fonts[fnum], buf, i); |
| i = 0; |
| } |
| |
| ulen = XFastConvertUtf8ToUcs((unsigned char*)string, num_bytes, &ucs); |
| |
| if (ulen < 1) ulen = 1; |
| |
| no_spc = XUtf8IsNonSpacing(ucs); |
| if (no_spc) { |
| ucs = no_spc; |
| } |
| |
| /* |
| * find the first encoding which can be used to |
| * draw the glyph |
| */ |
| fnum = first; |
| while (fnum < nb_font) { |
| if (fonts[fnum] && ucs2fontmap(glyph, ucs, encodings[fnum]) >= 0) { |
| if (encodings[fnum] != 0 || |
| (ucs >= ranges[fnum * 2] && |
| ucs <= ranges[fnum * 2 + 1])) { |
| break; |
| } |
| } |
| fnum++; |
| } |
| if (fnum == nb_font) { |
| /* the char is not valid in all encodings -> |
| * draw it using the first font :-( |
| */ |
| fnum = first; |
| ucs2fontmap(glyph, '?', encodings[fnum]); |
| } |
| |
| if (last_fnum != fnum || no_spc) { |
| x += XTextWidth16(fonts[last_fnum], buf, i); |
| i = 0; |
| (*buf).byte1 = glyph[0]; |
| (*buf).byte2 = glyph[1]; |
| if (no_spc) { |
| /* go back to draw the non-spacing char over the previous char */ |
| x -= XTextWidth16(fonts[fnum], buf, 1); |
| } |
| } else { |
| (*(buf + i)).byte1 = glyph[0]; |
| (*(buf + i)).byte2 = glyph[1]; |
| } |
| last_fnum = fnum; |
| i++; |
| string += ulen; |
| num_bytes -= ulen; |
| } |
| |
| x += XTextWidth16(fonts[last_fnum], buf, i); |
| |
| return x; |
| } |
| |
| /*****************************************************************************/ |
| /** get the X font and glyph ID of a UCS char **/ |
| /*****************************************************************************/ |
| int |
| XGetUtf8FontAndGlyph(XUtf8FontStruct *font_set, |
| unsigned int ucs, |
| XFontStruct **fnt, |
| unsigned short *id) { |
| |
| int x; |
| int *encodings; /* encodings array */ |
| XFontStruct **fonts; /* fonts array */ |
| int fnum; /* index of the current font in the fonts array*/ |
| int i; /* current byte in the XChar2b buffer */ |
| int first; /* first valid font index */ |
| int last_fnum; /* font index of the previous char */ |
| int nb_font; /* quantity of fonts in the font array */ |
| char glyph[2]; /* byte1 and byte2 value of the UTF-8 char */ |
| int *ranges; /* sub range of iso10646 */ |
| |
| nb_font = font_set->nb_font; |
| x = 0; |
| |
| if (nb_font < 1) { |
| /* there is no font in the font_set :-( */ |
| return -1; |
| } |
| |
| ranges = font_set->ranges; |
| fonts = font_set->fonts; |
| encodings = font_set->encodings; |
| i = 0; |
| fnum = 0; |
| |
| while(fnum < nb_font && !fonts[fnum]) fnum++; |
| if (fnum >= nb_font) { |
| /* there is no valid font for the X server */ |
| return -1; |
| } |
| |
| first = fnum; |
| last_fnum = fnum; |
| |
| /* |
| * find the first encoding which can be used to |
| * draw the glyph |
| */ |
| fnum = first; |
| while (fnum < nb_font) { |
| if (fonts[fnum] && ucs2fontmap(glyph, ucs, encodings[fnum]) >= 0) { |
| if (encodings[fnum] != 0 || |
| (ucs >= ranges[fnum * 2] && |
| ucs <= ranges[fnum * 2 + 1])) { |
| break; |
| } |
| } |
| fnum++; |
| } |
| if (fnum == nb_font) { |
| /* the char is not valid in all encodings -> |
| * draw it using the first font :-( |
| */ |
| fnum = first; |
| ucs2fontmap(glyph, '?', encodings[fnum]); |
| } |
| |
| *id = ((unsigned char)glyph[0] << 8) | (unsigned char)glyph[1] ; |
| *fnt = fonts[fnum]; |
| return 0; |
| } |
| |
| /*****************************************************************************/ |
| /** returns the pixel width of a UCS char **/ |
| /*****************************************************************************/ |
| int |
| XUtf8UcsWidth(XUtf8FontStruct *font_set, |
| unsigned int ucs) { |
| |
| int x; |
| int *encodings; /* encodings array */ |
| XFontStruct **fonts; /* fonts array */ |
| Fl_XChar2b buf[8]; /* drawing buffer */ |
| int fnum; /* index of the current font in the fonts array*/ |
| int i; /* current byte in the XChar2b buffer */ |
| int first; /* first valid font index */ |
| int last_fnum; /* font index of the previous char */ |
| int nb_font; /* quantity of fonts in the font array */ |
| char glyph[2]; /* byte1 and byte2 value of the UTF-8 char */ |
| int *ranges; /* sub range of iso10646 */ |
| |
| nb_font = font_set->nb_font; |
| x = 0; |
| |
| if (nb_font < 1) { |
| /* there is no font in the font_set :-( */ |
| return x; |
| } |
| |
| ranges = font_set->ranges; |
| fonts = font_set->fonts; |
| encodings = font_set->encodings; |
| i = 0; |
| fnum = 0; |
| |
| while(fnum < nb_font && !fonts[fnum]) fnum++; |
| if (fnum >= nb_font) { |
| /* there is no valid font for the X server */ |
| return x; |
| } |
| |
| first = fnum; |
| last_fnum = fnum; |
| |
| ucs = XUtf8IsNonSpacing(ucs); |
| |
| /* |
| * find the first encoding which can be used to |
| * draw the glyph |
| */ |
| fnum = first; |
| while (fnum < nb_font) { |
| if (fonts[fnum] && |
| ucs2fontmap(glyph, ucs, encodings[fnum]) >= 0) { |
| if (encodings[fnum] != 0 || (ucs >= ranges[fnum * 2] && |
| ucs <= ranges[fnum * 2 + 1])) { |
| break; |
| } |
| } |
| fnum++; |
| } |
| if (fnum == nb_font) { |
| /* the char is not valid in all encodings -> |
| * draw it using the first font :-( |
| */ |
| fnum = first; |
| ucs2fontmap(glyph, '?', encodings[fnum]); |
| } |
| |
| (*buf).byte1 = glyph[0]; |
| (*buf).byte2 = glyph[1]; |
| |
| x += XTextWidth16(fonts[fnum], buf, 1); |
| |
| return x; |
| } |
| |
| /*****************************************************************************/ |
| /** draw an UTF-8 string and clear the background. **/ |
| /*****************************************************************************/ |
| void |
| XUtf8DrawImageString(Display *display, |
| Drawable d, |
| XUtf8FontStruct *font_set, |
| GC gc, |
| int x, |
| int y, |
| const char *string, |
| int num_bytes) { |
| |
| /* FIXME: must be improved ! */ |
| int w; |
| int fill_style; |
| unsigned long foreground; |
| unsigned long background; |
| int function; |
| XGCValues xgcv; |
| |
| w = XUtf8TextWidth(font_set, string, num_bytes); |
| |
| XGetGCValues(display, gc, |
| GCFunction|GCForeground|GCBackground|GCFillStyle, &xgcv); |
| |
| function = xgcv.function; |
| fill_style = xgcv.fill_style; |
| foreground = xgcv.foreground; |
| background = xgcv.background; |
| |
| xgcv.function = GXcopy; |
| xgcv.foreground = background; |
| xgcv.background = foreground; |
| xgcv.fill_style = FillSolid; |
| |
| XChangeGC(display, gc, |
| GCFunction|GCForeground|GCBackground|GCFillStyle, &xgcv); |
| |
| XFillRectangle(display, d, gc, x, y - font_set->ascent, |
| (unsigned)w, (unsigned)(font_set->ascent + font_set->descent)); |
| |
| xgcv.function = function; |
| xgcv.foreground = foreground; |
| xgcv.background = background; |
| xgcv.fill_style = fill_style; |
| |
| XChangeGC(display, gc, |
| GCFunction|GCForeground|GCBackground|GCFillStyle, &xgcv); |
| |
| XUtf8DrawString(display, d, font_set, gc, x, y, string, num_bytes); |
| } |
| |
| /*****************************************************************************/ |
| /** free the XFontSet and others things created by XCreateUtf8FontSet **/ |
| /*****************************************************************************/ |
| void |
| XFreeUtf8FontStruct(Display *dpy, |
| XUtf8FontStruct *font_set) { |
| |
| int i; |
| i = 0; |
| while (i < font_set->nb_font) { |
| if (font_set->fonts[i]) { |
| XFreeFont(dpy, font_set->fonts[i]); |
| free(font_set->font_name_list[i]); |
| } |
| i++; |
| } |
| free(font_set->ranges); |
| free(font_set->font_name_list); |
| free(font_set->fonts); |
| free(font_set->encodings); |
| free(font_set); |
| } |
| |
| #endif /* X11 only */ |
| |
| /* |
| * End of "$Id: utf8Wrap.c 8401 2011-02-08 10:06:19Z ianmacarthur $". |
| */ |