DO NOT REPLY TO THIS MESSAGE. INSTEAD, POST ANY RESPONSES TO THE LINK BELOW.
[STR New]
Link: http://www.fltk.org/str.php?L1903
Version: 1.3-feature
Link: http://www.fltk.org/str.php?L1903
Version: 1.3-feature
Index: src/Fl_Font.H
===================================================================
--- src/Fl_Font.H (revision 6655)
+++ src/Fl_Font.H (working copy)
@@ -37,6 +37,30 @@
# if USE_XFT
typedef struct _XftFont XftFont;
+/**
+ This is a structure for an XFT font, with info about it's encoding and
+ character sizes. Each XftFontList has an array of these.
+*/
+typedef struct _XftMatch
+{
+ XftFont* font;
+ const char* enc_str; // Encoding name
+ const char* lang_str; // FontConfig language name
+ int enc_num; // XUTF8 encoding number
+ int ascent;
+ int descent;
+ int offset; // Adjustment from baseline
+} XftMatch;
+/**
+ This a structure that represents a collection of XFT fonts.
+*/
+typedef struct _XftFontList
+{
+ XftMatch* matches;
+ int count;
+ int ascent;
+ int descent;
+} XftFontList;
# elif !defined(WIN32) && !defined(__APPLE__)
# include <FL/Xutf8.h>
# endif // USE_XFT
@@ -73,8 +97,7 @@
char *q_name;
int size;
# elif USE_XFT
- XftFont* font;
- const char* encoding;
+ XftFontList* font;
Fl_Fontsize size;
FL_EXPORT Fl_Font_Descriptor(const char* xfontname);
# else
Index: src/fl_font_xft.cxx
===================================================================
--- src/fl_font_xft.cxx (revision 6655)
+++ src/fl_font_xft.cxx (working copy)
@@ -89,6 +89,42 @@
#define current_font (fl_fontsize->font)
+static const char* enc_strings[] =
+{
+ "iso8859-1", "fr",
+ "iso8859-2", "pl",
+ "iso8859-3", "eo",
+ "iso8859-4", "lt",
+ "iso8859-5", "bg",
+ "iso8859-6", "",
+ "iso8859-7", "gr",
+ "iso8859-8", "he",
+ "iso8859-9", "tr",
+ "iso8859-10", "",
+ "iso8859-11", "",
+ "iso8859-13", "lt",
+ "iso8859-14", "ga",
+ "iso8859-15", "fr",
+ "koi8-r", "ru-ru",
+ "big5-0", "zh-tw",
+ "ksc5601.1987-0", "ko",
+ "gb2312.1980-0", "zh-cn",
+ "jisx0201.1976-0", "ja",
+ "symbol", "",
+ "dingbats", "",
+ "koi8-u", "ru-ua",
+ "iso10646-1", "",
+ NULL
+};
+
+// Characters for estimating font height and width (as per Pango)
+static unsigned int extent_test_chars[] =
+{
+ '0', '1', '8', 'a', 'd', 'x', 'm', 'y', 'g', 'W', 'X', '\'', '_',
+ 0x00cd, 0x00d5, 0x0114, 0x0177, 0x0643, 0x304c, 0x672c, //
ÃÃÄÅ·ï»ãæ¬
+ '\0'
+};
+
Fl_Font fl_font_ = 0;
Fl_Fontsize fl_size_ = 0;
//XFontStruct* fl_xfont = 0;
@@ -98,6 +134,11 @@
const char* fl_encoding_ = "iso10646-1";
Fl_Font_Descriptor* fl_fontsize = 0;
+extern "C" {
+ int ucs2fontmap(char *s, unsigned int ucs, int enc);
+ int encoding_number(const char* enc);
+}
+
void fl_font(Fl_Font fnum, Fl_Fontsize size) {
if (fnum==-1) { // special case to stop font caching
fl_font_ = 0; fl_size_ = 0;
@@ -127,7 +168,36 @@
fl_xftfont = (void*)f->font;
}
-static XftFont* fontopen(const char* name, bool core) {
+static void fill_match_metrics(XftMatch* rec)
+{
+ rec->ascent = 0;
+ rec->descent = 0;
+ rec->offset = 0;
+
+ // Calculate ascent and descent from test glyphs
+ for (unsigned int* ucs = extent_test_chars; *ucs; ucs++)
+ {
+ // Ignore characters not used by current encoding
+ char dummy[2];
+ if (ucs2fontmap(dummy, *ucs, rec->enc_num) < 0) continue;
+ FcChar32 c = *ucs;
+ XGlyphInfo g;
+ XftTextExtents32(fl_display, rec->font, &c, 1, &g);
+ int ascent = g.y;
+ int descent = g.height - g.y;
+ if (ascent > rec->ascent) rec->ascent = ascent;
+ if (descent > rec->descent) rec->descent = descent;
+ }
+
+ // When ascent and descent not found, trust the font
+ if (rec->ascent == 0 && rec->descent == 0)
+ {
+ rec->ascent = rec->font->ascent;
+ rec->descent = rec->font->descent;
+ }
+}
+
+static XftFontList* fontopen(const char* name, bool core) {
// Check: does it look like we have been passed an old-school XLFD fontname?
bool is_xlfd = false;
int hyphen_count = 0;
@@ -142,9 +212,8 @@
fl_open_display();
- if(!is_xlfd) { // Not an XLFD - open as a XFT style name
- XftFont *the_font; // the font we will return;
XftPattern *fnt_pat = XftPatternCreate(); // the pattern we will use for
matching
+ if(!is_xlfd) { // Not an XLFD - open as a XFT style name
int slant = XFT_SLANT_ROMAN;
int weight = XFT_WEIGHT_MEDIUM;
@@ -205,17 +274,51 @@
XftPatternAddInteger(fnt_pat, XFT_WEIGHT, weight);
XftPatternAddInteger(fnt_pat, XFT_SLANT, slant);
XftPatternAddDouble (fnt_pat, XFT_PIXEL_SIZE, (double)fl_size_);
- XftPatternAddString (fnt_pat, XFT_ENCODING, fl_encoding_);
if (core) {
XftPatternAddBool(fnt_pat, XFT_CORE, FcTrue);
XftPatternAddBool(fnt_pat, XFT_RENDER, FcFalse);
}
+ }
+ else {
+ if(comma_count) { // multiple comma-separated XLFDs were passed
+ char *local_name = strdup(name); // duplicate the full name so we can
edit the copy
+ char *curr = local_name; // points to first name in string
+ char *nxt; // next name in string
+ do {
+ nxt = strchr(curr, ','); // find comma separator
+ if (nxt) {
+ *nxt = 0; // terminate first name
+ nxt++; // first char of next name
+ }
+
+ // Add the current name to the match pattern
+ XftPatternAddString(fnt_pat, XFT_XLFD, curr);
+
+ if(nxt) curr = nxt; // move onto next name (if it exists)
+
+ comma_count--; // decrement name sections count
+ } while (comma_count >= 0);
+ free(local_name); // release our local copy of font names
+ }
+ else { // single name was passed - add it directly
+ XftPatternAddString(fnt_pat, XFT_XLFD, name);
+ }
+ }
XftPattern *match_pat; // the best available match on the system
XftResult match_result; // the result of our matching attempt
- // query the system to find a match for this font
+ // query the system to find a matching font for each encoding
+ XftFontList* list = (XftFontList*)calloc(1, sizeof(XftFontList));
+ for (int n = 0; enc_strings[n]; n += 2) {
+ // Attempt to find a font for the required encoding
+ XftFont* fnt = NULL;
+ int enc_num = encoding_number(enc_strings[n]);
+ if (enc_num >= 0) {
+ XftPatternDel(fnt_pat, FC_LANG);
+ if (strlen(enc_strings[n+1]))
+ XftPatternAddString(fnt_pat, FC_LANG, enc_strings[n + 1]);
match_pat = XftFontMatch(fl_display, fl_screen, fnt_pat, &match_result);
#if 0 // the XftResult never seems to get set to anything... abandon this code?
@@ -252,8 +355,12 @@
free(picked_name);
#endif
+ if (match_pat) {
// open the matched font
- the_font = XftFontOpenPattern(fl_display, match_pat);
+ fnt = XftFontOpenPattern(fl_display, match_pat);
+ if (!fnt) XftPatternDestroy(match_pat);
+ }
+ }
#if 0 // diagnostic to print the "full name" of the font we actually opened.
This works.
FcChar8 *picked_name2 = FcNameUnparse(the_font->pattern);
@@ -261,35 +368,29 @@
free(picked_name2);
#endif
- XftPatternDestroy(fnt_pat);
-// XftPatternDestroy(match_pat); // FontConfig will destroy this resource for
us. We must not!
+// When a matching font is found, append to font list
+ if (fnt)
+ {
+ list->count ++;
+ list->matches = (XftMatch*)realloc(list->matches,
+ sizeof(XftMatch) * list->count);
- return the_font;
- }
- else { // We were passed a font name in XLFD format
- /* OksiD's X font code could handle being passed a comma separated list
- * of XLFD's. It then attempted to find which font was "best" from this
list.
- * But XftFontOpenXlfd can not do this, so if a list is passed, we just
- * terminate it at the first comma.
- * A "better" solution might be to use XftXlfdParse() on each of the passed
- * XLFD's to construct a "super-pattern" that incorporates attributes from
all
- * XLFD's and use that to perform a XftFontMatch(). Maybe...
- */
- char *local_name = strdup(name);
- if(comma_count) { // This means we were passed multiple XLFD's
- char *pc = strchr(local_name, ',');
- *pc = 0; // terminate the XLFD at the first comma
+ XftMatch& rec = list->matches[list->count - 1];
+ rec.font = fnt;
+ rec.enc_str = enc_strings[n];
+ rec.lang_str = enc_strings[n + 1];
+ rec.enc_num = enc_num;
+ fill_match_metrics(&rec);
+
+ // Update ascent and descent of combined font set
+ if (rec.ascent > list->ascent) list->ascent = rec.ascent;
+ if (rec.descent > list->descent) list->descent = rec.descent;
}
- XftFont *the_font = XftFontOpenXlfd(fl_display, fl_screen, local_name);
- free(local_name);
-#if 0 // diagnostic to print the "full name" of the font we actually opened.
This works.
-puts("Font Opened"); fflush(stdout);
- FcChar8 *picked_name2 = FcNameUnparse(the_font->pattern);
- printf("Open : %s\n", picked_name2); fflush(stdout);
- free(picked_name2);
-#endif
- return the_font;
}
+
+ // Tidy up the resources we allocated
+ XftPatternDestroy(fnt_pat);
+ return list;
} // end of fontopen
Fl_Font_Descriptor::Fl_Font_Descriptor(const char* name) {
@@ -304,6 +405,8 @@
Fl_Font_Descriptor::~Fl_Font_Descriptor() {
if (this == fl_fontsize) fl_fontsize = 0;
// XftFontClose(fl_display, font);
+ free(font->matches);
+ free(font);
}
int fl_height() {
@@ -316,26 +419,205 @@
else return -1;
}
-double fl_width(const char *str, int n) {
- if (!current_font) return -1.0;
+static int
+fl_width(XftFont* fnt, FcChar32* str, int n)
+{
XGlyphInfo i;
- XftTextExtentsUtf8(fl_display, current_font, (XftChar8 *)str, n, &i);
+ XftTextExtents32(fl_display, fnt, str, n, &i);
return i.xOff;
}
+// This function is used internally to avoid duplicate code in fl_width()
+// and fl_draw(). A non-NULL XftDraw parameter causes the actual string to
+// be drawn
+static double fl_width_utf8_(const char* str, int n,
+ XftDraw* draw = NULL, XftColor* color = NULL, int x = 0, int y = 0)
+{
+ XftMatch* matches; // fonts array
+ FcChar32 buf[128]; // drawing buffer
+ int i; // current byte in the UCS buffer
+ int fnum; // index of the current font in the fonts array
+ int last_fnum; // font index of the previous char
+ int count; // quantity of fonts in the font array
+ char glyph[2]; // byte1 and byte2 value of the UTF-8 char
+ int org_x = x;
+
+ if (!current_font) return -1.0;
+ count = current_font->count;
+
+ // There are no fonts in current_font
+ if (count < 1) return -1.0;
+
+ matches = current_font->matches;
+ i = 0;
+ fnum = 0;
+
+ while((fnum < count) && !matches[fnum].font) ++fnum;
+ if (fnum >= count) {
+ /* there is no valid font inside the XFT font set */
+ return 0;
+ }
+
+ last_fnum = fnum;
+
+ while (n > 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 **/
+ if (draw)
+ XftDrawString32(draw, color, matches[fnum].font, x, y, buf, i);
+ x += fl_width(matches[fnum].font, buf, i);
+ i = 0;
+ }
+
+ ulen = XFastConvertUtf8ToUcs((unsigned char*)str, n, &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
+ for (fnum = 0; fnum < count; fnum++)
+ {
+ if (matches[fnum].enc_num == 0) continue;
+ if (ucs2fontmap(glyph, ucs, matches[fnum].enc_num) >= 0) break;
+ }
+ if (fnum == count) {
+ // The char is invalid in all encodings, draw with the first font
+ fnum = 0;
+ ucs = '?';
+ }
+
+ if ((last_fnum != fnum) || no_spc) {
+ if (draw)
+ XftDrawString32(draw, color, matches[last_fnum].font, x, y, buf, i);
+ x += fl_width(matches[last_fnum].font, buf, i);
+ i = 0;
+ *buf = ucs;
+ if (no_spc) {
+ // Go back to draw the non-spacing char over the previous char
+ x -= fl_width(matches[fnum].font, buf, 1);
+ }
+ } else {
+ *(buf + i) = ucs;
+ }
+ last_fnum = fnum;
+ i++;
+ str += ulen;
+ n -= ulen;
+ }
+
+ if (draw)
+ XftDrawString32(draw, color, matches[last_fnum].font, x, y, buf, i);
+ x += fl_width(matches[fnum].font, buf, i);
+
+ return (x - org_x);
+}
+
+// This function is used internally to avoid duplicate code in fl_width()
+// and fl_drawUCS4(). A non-NULL XftDraw parameter causes the actual string to
+// be drawn
+static double fl_width_32_(const FcChar32* str, int n,
+ XftDraw* draw = NULL, XftColor* color = NULL, int x = 0, int y = 0)
+{
+ XftMatch* matches; // fonts array
+ FcChar32 buf[128]; // drawing buffer
+ int i; // current byte in the UCS buffer
+ int fnum; // index of the current font in the fonts array
+ int last_fnum; // font index of the previous char
+ int count; // quantity of fonts in the font array
+ char glyph[2]; // byte1 and byte2 value of the UTF-8 char
+ int org_x = x;
+
+ if (!current_font) return -1.0;
+ count = current_font->count;
+
+ // There are no fonts in current_font
+ if (count < 1) return -1.0;
+
+ matches = current_font->matches;
+ i = 0;
+ fnum = 0;
+
+ while((fnum < count) && !matches[fnum].font) ++fnum;
+ if (fnum >= count) {
+ /* there is no valid font inside the XFT font set */
+ return 0;
+ }
+
+ last_fnum = fnum;
+
+ while (n > 0) {
+ unsigned int ucs; /* Current UCS character */
+ unsigned int no_spc; /* Spacing char equivalent of a non-spacing char */
+
+ if (i > 120) {
+ /*** draw the buffer **/
+ if (draw)
+ XftDrawString32(draw, color, matches[fnum].font, x, y, buf, i);
+ x += fl_width(matches[fnum].font, buf, i);
+ i = 0;
+ }
+
+ ucs = *str;
+ no_spc = XUtf8IsNonSpacing(ucs);
+ if (no_spc) ucs = no_spc;
+
+ // Find the first encoding which can be used to draw the glyph
+ for (fnum = 0; fnum < count; fnum++)
+ {
+ if (matches[fnum].enc_num == 0) continue;
+ if (ucs2fontmap(glyph, ucs, matches[fnum].enc_num) >= 0) break;
+ }
+ if (fnum == count) {
+ // The char is invalid in all encodings, draw with the first font
+ fnum = 0;
+ ucs = '?';
+ }
+
+ if ((last_fnum != fnum) || no_spc) {
+ if (draw)
+ XftDrawString32(draw, color, matches[last_fnum].font, x, y, buf, i);
+ x += fl_width(matches[last_fnum].font, buf, i);
+ i = 0;
+ *buf = ucs;
+ if (no_spc) {
+ // Go back to draw the non-spacing char over the previous char
+ x -= fl_width(matches[fnum].font, buf, 1);
+ }
+ } else {
+ *(buf + i) = ucs;
+ }
+ last_fnum = fnum;
+ i++;
+ ++str;
+ --n;
+ }
+
+ if (draw)
+ XftDrawString32(draw, color, matches[last_fnum].font, x, y, buf, i);
+ x += fl_width(matches[fnum].font, buf, i);
+
+ return (x - org_x);
+}
+
+double fl_width(const char *str, int n) {
+ return fl_width_utf8_(str, n);
+}
+
double fl_width(uchar c) {
- return fl_width((const char *)(&c), 1);
+ return fl_width_utf8_((const char*)(&c), 1);
}
double fl_width(FcChar32 *str, int n) {
- if (!current_font) return -1.0;
- XGlyphInfo i;
- XftTextExtents32(fl_display, current_font, str, n, &i);
- return i.xOff;
+ return fl_width_32_(str, n);
}
double fl_width(unsigned int c) {
- return fl_width((FcChar32 *)(&c), 1);
+ return fl_width_32_((FcChar32 *)(&c), 1);
}
void fl_text_extents(const char *c, int n, int &dx, int &dy, int &w, int &h) {
@@ -344,13 +626,10 @@
dx = dy = 0;
return;
}
- XGlyphInfo gi;
- XftTextExtentsUtf8(fl_display, current_font, (XftChar8 *)c, n, &gi);
-
- w = gi.width;
- h = gi.height;
- dx = -gi.x;
- dy = -gi.y;
+ w = (int)fl_width_utf8_(c, n);
+ h = fl_height();
+ dx = 0;
+ dy = 0;
} // fl_text_extents
@@ -511,7 +790,7 @@
color.color.blue = ((int)b)*0x101;
color.color.alpha = 0xffff;
- XftDrawStringUtf8(draw, &color, current_font, x, y, (XftChar8 *)str, n);
+ fl_width_utf8_(str, n, draw, &color, x, y);
}
void fl_draw(const char* str, int n, float x, float y) {
@@ -549,7 +828,7 @@
color.color.blue = ((int)b)*0x101;
color.color.alpha = 0xffff;
- XftDrawString32(draw, &color, current_font, x, y, (FcChar32 *)str, n);
+ fl_width_32_(str, n, draw, &color, x, y);
}
Index: src/fl_font_x.cxx
===================================================================
--- src/fl_font_x.cxx (revision 6655)
+++ src/fl_font_x.cxx (working copy)
@@ -310,7 +310,6 @@
if (font_gc != fl_gc) {
if (!fl_xfont) fl_font(FL_HELVETICA, 14);
font_gc = fl_gc;
- XSetFont(fl_display, fl_gc, fl_xfont->fid);
}
// XDrawString(fl_display, fl_window, fl_gc, x, y, c, n);
XUtf8DrawString(fl_display, fl_window, fl_xfont, fl_gc, x, y, c, n);
_______________________________________________
fltk-dev mailing list
[email protected]
http://lists.easysw.com/mailman/listinfo/fltk-dev