1028 lines
28 KiB
C
1028 lines
28 KiB
C
/* "$Id$"
|
|
*
|
|
* Author: Jean-Marc Lienher ( http://oksid.ch )
|
|
* Copyright 2000-2003 by O'ksi'D.
|
|
*
|
|
* This library is free software. Distribution and use rights are outlined in
|
|
* the file "COPYING" which should have been included with this file. If this
|
|
* file is missing or damaged, see the license at:
|
|
*
|
|
* http://www.fltk.org/COPYING.php
|
|
*
|
|
* 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 "../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((int)(unsigned char)*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. **/
|
|
/*********************************************************************/
|
|
static 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 = 0;
|
|
|
|
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((const 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 ||
|
|
((int)ucs >= ranges[fnum * 2] && (int)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((const 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 ||
|
|
((int)ucs >= ranges[fnum * 2] &&
|
|
(int)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! */
|
|
/* FC: the man does not specify error codes for it, but X will generate X errors like BadGC or BadFont. */
|
|
|
|
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((const 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 ||
|
|
((int)ucs >= ranges[fnum * 2] &&
|
|
(int)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((const 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 ||
|
|
((int)ucs >= ranges[fnum * 2] &&
|
|
(int)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
|
|
fl_XGetUtf8FontAndGlyph(XUtf8FontStruct *font_set,
|
|
unsigned int ucs,
|
|
XFontStruct **fnt,
|
|
unsigned short *id) {
|
|
|
|
int *encodings; /* encodings array */
|
|
XFontStruct **fonts; /* fonts array */
|
|
int fnum; /* index of the current font in the fonts array*/
|
|
int first; /* first valid font index */
|
|
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 -1;
|
|
}
|
|
|
|
ranges = font_set->ranges;
|
|
fonts = font_set->fonts;
|
|
encodings = font_set->encodings;
|
|
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;
|
|
|
|
/*
|
|
* 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 ||
|
|
((int)ucs >= ranges[fnum * 2] &&
|
|
(int)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 first; /* first valid font index */
|
|
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 */
|
|
unsigned int no_spc;
|
|
|
|
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;
|
|
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;
|
|
|
|
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 || ((int)ucs >= ranges[fnum * 2] &&
|
|
(int)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$".
|
|
*/
|